From da192a20c634c5d1a65178945b5d5d5e6c5da5aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20R=C3=B6hling?= Date: Fri, 2 Feb 2024 17:42:32 +0100 Subject: [PATCH] New upstream version 3.28.2 --- Help/command/get_cmake_property.rst | 6 +- Help/command/get_source_file_property.rst | 14 +- Help/command/get_target_property.rst | 16 +- Help/command/get_test_property.rst | 14 +- Help/command/set_directory_properties.rst | 5 +- Help/command/set_target_properties.rst | 6 +- Help/command/set_tests_properties.rst | 5 +- Help/command/string.rst | 2 +- Help/manual/cmake-cxxmodules.7.rst | 4 + Help/manual/cmake-language.7.rst | 2 +- Help/manual/cmake-toolchains.7.rst | 10 +- Help/manual/ctest.1.rst | 48 +- Help/prop_sf/SKIP_UNITY_BUILD_INCLUSION.rst | 4 + Help/prop_tgt/UNITY_BUILD.rst | 5 + Help/release/3.28.rst | 12 +- Modules/CheckLanguage.cmake | 28 +- Modules/ExternalProject.cmake | 14 +- Modules/FeatureSummary.cmake | 2 +- Modules/FindBoost.cmake | 3 +- Modules/FindCUDAToolkit.cmake | 6 +- Modules/FindFreetype.cmake | 98 ---- Modules/FindMatlab.cmake | 160 ++++--- .../Internal/CMakeCUDAArchitecturesAll.cmake | 14 +- Modules/UsePkgConfig.cmake | 9 +- Source/CMakeVersion.cmake | 4 +- Source/CPack/cmCPackSTGZGenerator.cxx | 2 - Source/CTest/cmCTestBZR.cxx | 31 +- Source/CTest/cmCTestBuildAndTestHandler.cxx | 15 +- Source/CTest/cmCTestBuildHandler.cxx | 291 ++++++------ Source/CTest/cmCTestBuildHandler.h | 6 +- Source/CTest/cmCTestCVS.cxx | 18 +- Source/CTest/cmCTestConfigureHandler.cxx | 2 +- Source/CTest/cmCTestCoverageHandler.cxx | 111 ++++- Source/CTest/cmCTestGIT.cxx | 130 +++--- Source/CTest/cmCTestHG.cxx | 35 +- Source/CTest/cmCTestLaunch.cxx | 126 +++-- Source/CTest/cmCTestLaunch.h | 5 +- Source/CTest/cmCTestLaunchReporter.cxx | 50 +- Source/CTest/cmCTestLaunchReporter.h | 4 +- Source/CTest/cmCTestP4.cxx | 66 +-- Source/CTest/cmCTestP4.h | 2 +- Source/CTest/cmCTestSVN.cxx | 36 +- Source/CTest/cmCTestSVN.h | 2 +- Source/CTest/cmCTestScriptHandler.cxx | 84 ++-- Source/CTest/cmCTestVC.cxx | 45 +- Source/CTest/cmCTestVC.h | 9 +- .../cmCTestResourceGroupsLexer.cxx | 4 - .../cmCTestResourceGroupsLexer.in.l | 4 - Source/cmCTest.cxx | 429 ++++++++---------- Source/cmCTest.h | 16 +- Source/cmComputeLinkInformation.cxx | 7 +- Source/cmComputeLinkInformation.h | 2 +- Source/cmDyndepCollation.cxx | 3 +- Source/cmExecuteProcessCommand.cxx | 402 ++++++++-------- Source/cmExportBuildFileGenerator.cxx | 31 +- Source/cmExportBuildFileGenerator.h | 6 +- Source/cmExportFileGenerator.cxx | 9 +- Source/cmExportFileGenerator.h | 5 +- Source/cmExportInstallFileGenerator.cxx | 15 +- Source/cmExportInstallFileGenerator.h | 6 +- Source/cmExportTryCompileFileGenerator.h | 5 +- Source/cmFindLibraryCommand.cxx | 8 +- Source/cmGeneratorTarget.cxx | 28 +- Source/cmGlobalGenerator.cxx | 30 +- Source/cmGlobalGenerator.h | 1 + Source/cmGlobalNinjaGenerator.cxx | 1 + Source/cmImportedCxxModuleInfo.cxx | 7 +- Source/cmInstallExportGenerator.cxx | 5 +- Source/cmLocalGenerator.cxx | 9 + Source/cmMakefileTargetGenerator.cxx | 7 +- Source/cmNinjaTargetGenerator.cxx | 18 +- Source/cmNinjaTargetGenerator.h | 2 +- Source/cmOutputConverter.cxx | 9 + Source/cmOutputConverter.h | 5 +- Source/cmProcessTools.cxx | 82 ++-- Source/cmProcessTools.h | 8 +- Source/cmQtAutoGenInitializer.cxx | 13 +- Source/cmState.cxx | 10 + Source/cmState.h | 3 + Source/cmSystemTools.cxx | 290 +++++------- Source/cmSystemTools.h | 21 +- Source/cmUVProcessChain.cxx | 19 +- Source/cmUVProcessChain.h | 6 +- Source/cmVisualStudio10TargetGenerator.cxx | 11 +- Source/cmake.cxx | 7 +- Source/cmcmd.cxx | 102 +++-- Tests/CMakeLib/testUVProcessChain.cxx | 5 +- Tests/CMakeLib/testUVProcessChainHelper.cxx | 4 + Tests/CMakeOnly/CMakeLists.txt | 7 + .../CheckLanguageHIPPlatform/CMakeLists.txt | 17 + .../CheckLanguageHIPPlatform2/CMakeLists.txt | 14 + Tests/Cuda/CMakeLists.txt | 1 + Tests/Cuda/Toolkit/CMakeLists.txt | 17 + Tests/CudaOnly/CMakeLists.txt | 1 + Tests/CudaOnly/Toolkit/CMakeLists.txt | 20 +- .../LoadCommand/CMakeCommands/cmTestCommand.c | 13 +- .../CMakeCommands/cmTestCommand.c | 15 +- .../AutogenTimestampDeps/CMakeLists.txt | 11 + .../AutogenTimestampDeps/ProjectInfo.hpp.in | 6 + .../cmake/UpdateProjectInfo.cmake | 2 + .../AutogenTimestampDeps/src/CMakeLists.txt | 4 + .../AutogenTimestampDeps/src/main.cpp | 5 + Tests/QtAutogen/Tests.cmake | 1 + .../BuildDepends/CustomCommandDepfile.cmake | 11 + .../DepfileSubdirWithSpace/CMakeLists.txt | 2 + .../path with space/CMakeLists.txt | 9 + .../ExportBuildCxxModules-check.cmake | 12 +- .../ExportBuildCxxModulesTargets-check.cmake | 40 ++ .../ExportBuildCxxModulesTargets.cmake | 21 + .../ExportInstallCxxModules-check.cmake | 10 +- Tests/RunCMake/CXXModules/RunCMakeTest.cmake | 4 + .../import-from-object/CMakeLists.txt | 16 + .../examples/import-from-object/object-a.cxx | 2 + .../examples/import-from-object/object-b.cxx | 1 + .../examples/scan_properties/CMakeLists.txt | 8 +- .../{never_scan.cxx => never_scan.ixx} | 0 .../examples/unity-build/CMakeLists.txt | 26 ++ .../examples/unity-build/importable.cxx | 10 + .../CXXModules/examples/unity-build/main.cxx | 6 + .../CXXModules/examples/unity-build/unity.h | 7 + .../examples/unity-build/unity1.cxx | 8 + .../examples/unity-build/unity2.cxx | 10 + .../examples/vs-without-flags/CMakeLists.txt | 22 + .../examples/vs-without-flags/main.cxx | 6 + .../examples/vs-without-flags/module.cxx | 6 + .../Ninja/LINK_OPTIONSWithNewlines.cmake | 7 + Tests/RunCMake/Ninja/RunCMakeTest.cmake | 2 + .../ImportedTargetPerConfig.cmake | 27 ++ .../target_link_libraries/RunCMakeTest.cmake | 1 + Utilities/IWYU/mapping.imp | 4 - Utilities/Scripts/update-zlib.bash | 2 +- Utilities/cmzlib/README | 4 +- Utilities/cmzlib/compress.c | 6 +- Utilities/cmzlib/crc32.c | 33 +- Utilities/cmzlib/deflate.c | 218 ++++----- Utilities/cmzlib/deflate.h | 4 +- Utilities/cmzlib/gzlib.c | 2 +- Utilities/cmzlib/gzread.c | 8 +- Utilities/cmzlib/gzwrite.c | 2 +- Utilities/cmzlib/inflate.c | 7 +- Utilities/cmzlib/inftrees.c | 4 +- Utilities/cmzlib/inftrees.h | 2 +- Utilities/cmzlib/trees.c | 123 +++-- Utilities/cmzlib/uncompr.c | 4 +- Utilities/cmzlib/zconf.h | 19 +- Utilities/cmzlib/zlib.h | 20 +- Utilities/cmzlib/zutil.c | 16 +- Utilities/cmzlib/zutil.h | 1 + 148 files changed, 2251 insertions(+), 1852 deletions(-) create mode 100644 Tests/CMakeOnly/CheckLanguageHIPPlatform/CMakeLists.txt create mode 100644 Tests/CMakeOnly/CheckLanguageHIPPlatform2/CMakeLists.txt create mode 100644 Tests/QtAutogen/AutogenTimestampDeps/CMakeLists.txt create mode 100644 Tests/QtAutogen/AutogenTimestampDeps/ProjectInfo.hpp.in create mode 100644 Tests/QtAutogen/AutogenTimestampDeps/cmake/UpdateProjectInfo.cmake create mode 100644 Tests/QtAutogen/AutogenTimestampDeps/src/CMakeLists.txt create mode 100644 Tests/QtAutogen/AutogenTimestampDeps/src/main.cpp create mode 100644 Tests/RunCMake/BuildDepends/DepfileSubdirWithSpace/CMakeLists.txt create mode 100644 Tests/RunCMake/BuildDepends/DepfileSubdirWithSpace/path with space/CMakeLists.txt create mode 100644 Tests/RunCMake/CXXModules/ExportBuildCxxModulesTargets-check.cmake create mode 100644 Tests/RunCMake/CXXModules/ExportBuildCxxModulesTargets.cmake create mode 100644 Tests/RunCMake/CXXModules/examples/import-from-object/CMakeLists.txt create mode 100644 Tests/RunCMake/CXXModules/examples/import-from-object/object-a.cxx create mode 100644 Tests/RunCMake/CXXModules/examples/import-from-object/object-b.cxx rename Tests/RunCMake/CXXModules/examples/scan_properties/{never_scan.cxx => never_scan.ixx} (100%) create mode 100644 Tests/RunCMake/CXXModules/examples/unity-build/CMakeLists.txt create mode 100644 Tests/RunCMake/CXXModules/examples/unity-build/importable.cxx create mode 100644 Tests/RunCMake/CXXModules/examples/unity-build/main.cxx create mode 100644 Tests/RunCMake/CXXModules/examples/unity-build/unity.h create mode 100644 Tests/RunCMake/CXXModules/examples/unity-build/unity1.cxx create mode 100644 Tests/RunCMake/CXXModules/examples/unity-build/unity2.cxx create mode 100644 Tests/RunCMake/CXXModules/examples/vs-without-flags/CMakeLists.txt create mode 100644 Tests/RunCMake/CXXModules/examples/vs-without-flags/main.cxx create mode 100644 Tests/RunCMake/CXXModules/examples/vs-without-flags/module.cxx create mode 100644 Tests/RunCMake/Ninja/LINK_OPTIONSWithNewlines.cmake create mode 100644 Tests/RunCMake/target_link_libraries/ImportedTargetPerConfig.cmake diff --git a/Help/command/get_cmake_property.rst b/Help/command/get_cmake_property.rst index b1d18a0d8..9f78a86cd 100644 --- a/Help/command/get_cmake_property.rst +++ b/Help/command/get_cmake_property.rst @@ -5,11 +5,11 @@ Get a global property of the CMake instance. .. code-block:: cmake - get_cmake_property( ) + get_cmake_property( ) Gets a global property from the CMake instance. The value of -the ```` is stored in the variable ````. -If the property is not found, ```` will be set to ``NOTFOUND``. +the ```` is stored in the specified ````. +If the property is not found, ```` will be set to ``NOTFOUND``. See the :manual:`cmake-properties(7)` manual for available properties. In addition to global properties, this command (for historical reasons) diff --git a/Help/command/get_source_file_property.rst b/Help/command/get_source_file_property.rst index e83e9c27b..a7e5191a3 100644 --- a/Help/command/get_source_file_property.rst +++ b/Help/command/get_source_file_property.rst @@ -9,14 +9,12 @@ Get a property for a source file. [DIRECTORY | TARGET_DIRECTORY ] ) -Gets a property from a source file. The value of the property is -stored in the specified ````. If the source property is not found, -the behavior depends on whether it has been defined to be an ``INHERITED`` -property or not (see :command:`define_property`). Non-inherited properties -will set ``variable`` to ``NOTFOUND``, whereas inherited properties will search -the relevant parent scope as described for the :command:`define_property` -command and if still unable to find the property, ``variable`` will be set to -an empty string. +Gets a property from a source file. The value of the property is stored in +the specified ````. If the ```` is not a source file, or the +source property is not found, ```` will be set to ``NOTFOUND``. +If the source property was defined to be an ``INHERITED`` property (see +:command:`define_property`), the search will include the relevant parent +scopes, as described for the :command:`define_property` command. By default, the source file's property will be read from the current source directory's scope. diff --git a/Help/command/get_target_property.rst b/Help/command/get_target_property.rst index 8c6dcb169..1554a8595 100644 --- a/Help/command/get_target_property.rst +++ b/Help/command/get_target_property.rst @@ -5,16 +5,14 @@ Get a property from a target. .. code-block:: cmake - get_target_property( target property) + get_target_property( ) -Get a property from a target. The value of the property is stored in -the variable ````. If the target property is not found, the behavior -depends on whether it has been defined to be an ``INHERITED`` property -or not (see :command:`define_property`). Non-inherited properties will -set ```` to ``-NOTFOUND``, whereas inherited properties will search -the relevant parent scope as described for the :command:`define_property` -command and if still unable to find the property, ```` will be set to -an empty string. +Get a property from a target. The value of the property is stored in the +specified ````. If the target property is not found, ```` +will be set to ``-NOTFOUND``. If the target property was defined to +be an ``INHERITED`` property (see :command:`define_property`), the search will +include the relevant parent scopes, as described for the +:command:`define_property` command. Use :command:`set_target_properties` to set target property values. Properties are usually used to control how a target is built, but some diff --git a/Help/command/get_test_property.rst b/Help/command/get_test_property.rst index 1fcf24e4a..3f1a64cc6 100644 --- a/Help/command/get_test_property.rst +++ b/Help/command/get_test_property.rst @@ -5,16 +5,14 @@ Get a property of the test. .. code-block:: cmake - get_test_property(test property [DIRECTORY ] VAR) + get_test_property( [DIRECTORY ] ) Get a property from the test. The value of the property is stored in -the variable ``VAR``. If the test property is not found, the behavior -depends on whether it has been defined to be an ``INHERITED`` property -or not (see :command:`define_property`). Non-inherited properties will -set ``VAR`` to "NOTFOUND", whereas inherited properties will search the -relevant parent scope as described for the :command:`define_property` -command and if still unable to find the property, ``VAR`` will be set to -an empty string. +the specified ````. If the ```` is not defined, or the +test property is not found, ```` will be set to ``NOTFOUND``. +If the test property was defined to be an ``INHERITED`` property (see +:command:`define_property`), the search will include the relevant parent +scopes, as described for the :command:`define_property` command. For a list of standard properties you can type :option:`cmake --help-property-list`. diff --git a/Help/command/set_directory_properties.rst b/Help/command/set_directory_properties.rst index 93ad39b3b..6d9480849 100644 --- a/Help/command/set_directory_properties.rst +++ b/Help/command/set_directory_properties.rst @@ -5,9 +5,10 @@ Set properties of the current directory and subdirectories. .. code-block:: cmake - set_directory_properties(PROPERTIES prop1 value1 [prop2 value2] ...) + set_directory_properties(PROPERTIES [ ] ...) -Sets properties of the current directory and its subdirectories in key-value pairs. +Sets properties of the current directory and its subdirectories in key-value +pairs. See also the :command:`set_property(DIRECTORY)` command. diff --git a/Help/command/set_target_properties.rst b/Help/command/set_target_properties.rst index 874788b2f..5357575ba 100644 --- a/Help/command/set_target_properties.rst +++ b/Help/command/set_target_properties.rst @@ -5,9 +5,9 @@ Targets can have properties that affect how they are built. .. code-block:: cmake - set_target_properties(target1 target2 ... - PROPERTIES prop1 value1 - prop2 value2 ...) + set_target_properties( ... + PROPERTIES + [ ] ...) Sets properties on targets. The syntax for the command is to list all the targets you want to change, and then provide the values you want to diff --git a/Help/command/set_tests_properties.rst b/Help/command/set_tests_properties.rst index da750e368..a21f746e9 100644 --- a/Help/command/set_tests_properties.rst +++ b/Help/command/set_tests_properties.rst @@ -5,7 +5,10 @@ Set a property of the tests. .. code-block:: cmake - set_tests_properties(test1 [test2...] PROPERTIES prop1 value1 prop2 value2) + set_tests_properties(... + [DIRECTORY ] + PROPERTIES + [ ]...) Sets a property for the tests. If the test is not found, CMake will report an error. diff --git a/Help/command/string.rst b/Help/command/string.rst index 0e69b27eb..2f01653f7 100644 --- a/Help/command/string.rst +++ b/Help/command/string.rst @@ -22,7 +22,7 @@ Synopsis string(`JOIN`_ [...]) string(`TOLOWER`_ ) string(`TOUPPER`_ ) - string(`LENGTH`_ ) + string(`LENGTH `_ ) string(`SUBSTRING`_ ) string(`STRIP`_ ) string(`GENEX_STRIP`_ ) diff --git a/Help/manual/cmake-cxxmodules.7.rst b/Help/manual/cmake-cxxmodules.7.rst index b4c9cf1f0..3ee664500 100644 --- a/Help/manual/cmake-cxxmodules.7.rst +++ b/Help/manual/cmake-cxxmodules.7.rst @@ -30,6 +30,10 @@ following queries. The first query that provides a yes/no answer is used. - Otherwise, the source file will be scanned if the compiler and generator support scanning. See policy :policy:`CMP0155`. +Note that any scanned source will be excluded from any unity build (see +:prop_tgt:`UNITY_BUILD`) because module-related statements can only happen at +one place within a C++ translation unit. + Compiler Support ================ diff --git a/Help/manual/cmake-language.7.rst b/Help/manual/cmake-language.7.rst index d0774cb98..dba953db0 100644 --- a/Help/manual/cmake-language.7.rst +++ b/Help/manual/cmake-language.7.rst @@ -224,7 +224,7 @@ For example:: They interpret the opening bracket as the start of an `Unquoted Argument`_. -.. _`Lua`: http://www.lua.org/ +.. _`Lua`: https://www.lua.org/ .. _`Quoted Argument`: diff --git a/Help/manual/cmake-toolchains.7.rst b/Help/manual/cmake-toolchains.7.rst index e32bd29ae..1ebdf85ea 100644 --- a/Help/manual/cmake-toolchains.7.rst +++ b/Help/manual/cmake-toolchains.7.rst @@ -583,7 +583,7 @@ generator is recommended. The :generator:`Unix Makefiles` or :generator:`Ninja` generators can also be used, but they require the project to handle more areas like target CPU selection and code signing. -Any of the three systems can be targeted by setting the +Any of the Apple device platforms can be targeted by setting the :variable:`CMAKE_SYSTEM_NAME` variable to a value from the table below. By default, the latest Device SDK is chosen. As for all Apple platforms, a different SDK (e.g. a simulator) can be selected by setting the @@ -611,9 +611,11 @@ Variable :variable:`CMAKE_OSX_ARCHITECTURES` can be used to set architectures for both device and simulator. Variable :variable:`CMAKE_OSX_DEPLOYMENT_TARGET` can be used to set an iOS/tvOS/visionOS/watchOS deployment target. -Next configuration will install fat 5 architectures iOS library -and add the ``-miphoneos-version-min=9.3``/``-mios-simulator-version-min=9.3`` -flags to the compiler: +The next example installs five architectures in a universal binary for an iOS +library. It adds the relevant ``-miphoneos-version-min=9.3`` or +``-mios-simulator-version-min=9.3`` compiler flag where appropriate. +Note that the :variable:`CMAKE_IOS_INSTALL_COMBINED` variable used in the +example is now deprecated, so this approach is no longer recommended. .. code-block:: console diff --git a/Help/manual/ctest.1.rst b/Help/manual/ctest.1.rst index a5b27b61c..5512c6116 100644 --- a/Help/manual/ctest.1.rst +++ b/Help/manual/ctest.1.rst @@ -1592,17 +1592,20 @@ that running several of these tests at once does not exhaust the GPU's memory pool. Please note that CTest has no concept of what a GPU is or how much memory it -has, nor does it have any way of communicating with a GPU to retrieve this -information or perform any memory management. CTest simply keeps track of a -list of abstract resource types, each of which has a certain number of slots -available for tests to use. Each test specifies the number of slots that it -requires from a certain resource, and CTest then schedules them in a way that -prevents the total number of slots in use from exceeding the listed capacity. -When a test is executed, and slots from a resource are allocated to that test, -tests may assume that they have exclusive use of those slots for the duration -of the test's process. - -The CTest resource allocation feature consists of two inputs: +has. It does not have any way of communicating with a GPU to retrieve this +information or perform any memory management, although the project can define +a test that provides details about the test machine (see +:ref:`ctest-resource-dynamically-generated-spec-file`). + +CTest keeps track of a list of abstract resource types, each of which has a +certain number of slots available for tests to use. Each test specifies the +number of slots that it requires from a certain resource, and CTest then +schedules them in a way that prevents the total number of slots in use from +exceeding the listed capacity. When a test is executed, and slots from a +resource are allocated to that test, tests may assume that they have exclusive +use of those slots for the duration of the test's process. + +The CTest resource allocation feature consists of at least two inputs: * The :ref:`resource specification file `, described below, which describes the resources available on the system. @@ -1643,15 +1646,20 @@ properties to indicate a skipped test. Resource Specification File --------------------------- -The resource specification file is a JSON file which is passed to CTest, either -on the command line as :option:`ctest --resource-spec-file`, or as the -``RESOURCE_SPEC_FILE`` argument of :command:`ctest_test`. If a dashboard script -is used and ``RESOURCE_SPEC_FILE`` is not specified, the value of -:variable:`CTEST_RESOURCE_SPEC_FILE` in the dashboard script is used instead. -If :option:`--resource-spec-file `, ``RESOURCE_SPEC_FILE``, -and :variable:`CTEST_RESOURCE_SPEC_FILE` in the dashboard script are not specified, -the value of :variable:`CTEST_RESOURCE_SPEC_FILE` in the CMake build is used -instead. If none of these are specified, no resource spec file is used. +The resource specification file is a JSON file which is passed to CTest in one +of a number of ways. It can be specified on the command line with the +:option:`ctest --resource-spec-file` option, it can be given using the +``RESOURCE_SPEC_FILE`` argument of :command:`ctest_test`, or it can be +generated dynamically as part of test execution (see +:ref:`ctest-resource-dynamically-generated-spec-file`). + +If a dashboard script is used and ``RESOURCE_SPEC_FILE`` is not specified, the +value of :variable:`CTEST_RESOURCE_SPEC_FILE` in the dashboard script is used +instead. If :option:`--resource-spec-file `, +``RESOURCE_SPEC_FILE``, and :variable:`CTEST_RESOURCE_SPEC_FILE` in the +dashboard script are not specified, the value of +:variable:`CTEST_RESOURCE_SPEC_FILE` in the CMake build is used instead. +If none of these are specified, no resource spec file is used. The resource specification file must be a JSON object. All examples in this document assume the following resource specification file: diff --git a/Help/prop_sf/SKIP_UNITY_BUILD_INCLUSION.rst b/Help/prop_sf/SKIP_UNITY_BUILD_INCLUSION.rst index ae526ac1d..38a0a7800 100644 --- a/Help/prop_sf/SKIP_UNITY_BUILD_INCLUSION.rst +++ b/Help/prop_sf/SKIP_UNITY_BUILD_INCLUSION.rst @@ -11,3 +11,7 @@ in the same way as it would with unity builds disabled. This property helps with "ODR (One definition rule)" problems where combining a particular source file with others might lead to build errors or other unintended side effects. + +Note that sources which are scanned for C++ modules (see +:manual:`cmake-cxxmodules(7)`) are not eligible for unity build inclusion and +will automatically be excluded. diff --git a/Help/prop_tgt/UNITY_BUILD.rst b/Help/prop_tgt/UNITY_BUILD.rst index f827a20a1..9d68250b7 100644 --- a/Help/prop_tgt/UNITY_BUILD.rst +++ b/Help/prop_tgt/UNITY_BUILD.rst @@ -64,6 +64,11 @@ a number of measures to help address such problems: :prop_sf:`INCLUDE_DIRECTORIES` source property will not be combined into a unity source. +* Any source file which is scanned for C++ module sources via + :prop_tgt:`CXX_SCAN_FOR_MODULES`, :prop_sf:`CXX_SCAN_FOR_MODULES`, or + membership of a ``CXX_MODULES`` file set will not be combined into a unity + source. See :manual:`cmake-cxxmodules(7)` for details. + * Projects can prevent an individual source file from being combined into a unity source by setting its :prop_sf:`SKIP_UNITY_BUILD_INCLUSION` source property to true. This can be a more effective way to prevent diff --git a/Help/release/3.28.rst b/Help/release/3.28.rst index f002cd258..05918ec30 100644 --- a/Help/release/3.28.rst +++ b/Help/release/3.28.rst @@ -116,12 +116,6 @@ Modules Additionally, the :command:`ExternalProject_Add_Step` command has been updated to support the new ``JOB_SERVER_AWARE`` option. -* The :module:`ExternalProject` module now declares ``BYPRODUCTS`` for the - downloaded file for generated ``download`` steps. Previously, if multiple - external projects downloaded to the same file, hash verification could fail. - Now, when using the :ref:`Ninja Generators`, this scenario is detected and - Ninja will raise an error stating that multiple rules generate the same file. - * The :module:`FetchContent` module's :command:`FetchContent_Declare` command gained an ``EXCLUDE_FROM_ALL`` option, which propagates through to the :command:`add_subdirectory` call made by @@ -207,9 +201,9 @@ Updates Changes made since CMake 3.28.0 include the following. -3.28.1 ------- +3.28.1, 3.28.2 +-------------- -* This version made no changes to documented features or interfaces. +* These versions made no changes to documented features or interfaces. Some implementation updates were made to support ecosystem changes and/or fix regressions. diff --git a/Modules/CheckLanguage.cmake b/Modules/CheckLanguage.cmake index 94948b995..bad359042 100644 --- a/Modules/CheckLanguage.cmake +++ b/Modules/CheckLanguage.cmake @@ -41,6 +41,12 @@ or :command:`project` commands: not be set without also setting :variable:`CMAKE__COMPILER` to a NVCC compiler. + :variable:`CMAKE__PLATFORM ` + This variable is set to the detected GPU platform when ```` is ``HIP``. + + If the variable is already set its value is always preserved. Only compatible values + will be considered for :variable:`CMAKE__COMPILER`. + For example: .. code-block:: cmake @@ -66,15 +72,23 @@ macro(check_language lang) set(extra_compiler_variables) if("${lang}" MATCHES "^(CUDA|HIP)$" AND NOT CMAKE_GENERATOR MATCHES "Visual Studio") - set(extra_compiler_variables "set(CMAKE_CUDA_HOST_COMPILER \\\"\${CMAKE_CUDA_HOST_COMPILER}\\\")") + set(extra_compiler_variables "set(CMAKE_${lang}_HOST_COMPILER \\\"\${CMAKE_${lang}_HOST_COMPILER}\\\")") + endif() + + if("${lang}" STREQUAL "HIP") + list(APPEND extra_compiler_variables "set(CMAKE_${lang}_PLATFORM \\\"\${CMAKE_${lang}_PLATFORM}\\\")") endif() + list(TRANSFORM extra_compiler_variables PREPEND "\"") + list(TRANSFORM extra_compiler_variables APPEND "\\n\"") + list(JOIN extra_compiler_variables "\n " extra_compiler_variables) + set(_cl_content "cmake_minimum_required(VERSION ${CMAKE_VERSION}) project(Check${lang} ${lang}) file(WRITE \"\${CMAKE_CURRENT_BINARY_DIR}/result.cmake\" \"set(CMAKE_${lang}_COMPILER \\\"\${CMAKE_${lang}_COMPILER}\\\")\\n\" - \"${extra_compiler_variables}\\n\" + ${extra_compiler_variables} )" ) @@ -95,6 +109,11 @@ file(WRITE \"\${CMAKE_CURRENT_BINARY_DIR}/result.cmake\" else() set(_D_CMAKE_TOOLCHAIN_FILE "") endif() + if(CMAKE_${lang}_PLATFORM) + set(_D_CMAKE_LANG_PLATFORM "-DCMAKE_${lang}_PLATFORM:STRING=${CMAKE_${lang}_PLATFORM}") + else() + set(_D_CMAKE_LANG_PLATFORM "") + endif() execute_process( WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/Check${lang} COMMAND ${CMAKE_COMMAND} . -G ${CMAKE_GENERATOR} @@ -103,6 +122,7 @@ file(WRITE \"\${CMAKE_CURRENT_BINARY_DIR}/result.cmake\" ${_D_CMAKE_GENERATOR_INSTANCE} ${_D_CMAKE_MAKE_PROGRAM} ${_D_CMAKE_TOOLCHAIN_FILE} + ${_D_CMAKE_LANG_PLATFORM} OUTPUT_VARIABLE _cl_output ERROR_VARIABLE _cl_output RESULT_VARIABLE _cl_result @@ -130,6 +150,10 @@ file(WRITE \"\${CMAKE_CURRENT_BINARY_DIR}/result.cmake\" mark_as_advanced(CMAKE_${lang}_HOST_COMPILER) endif() + if(CMAKE_${lang}_PLATFORM) + set(CMAKE_${lang}_PLATFORM "${CMAKE_${lang}_PLATFORM}" CACHE STRING "${lang} platform") + mark_as_advanced(CMAKE_${lang}_PLATFORM) + endif() endif() endmacro() diff --git a/Modules/ExternalProject.cmake b/Modules/ExternalProject.cmake index 3ec0557b4..a5dceaa3c 100644 --- a/Modules/ExternalProject.cmake +++ b/Modules/ExternalProject.cmake @@ -2825,7 +2825,6 @@ function(_ep_add_download_command name) set(comment) set(work_dir) set(extra_repo_info) - set(byproduct_file) if(cmd_set) set(work_dir ${download_dir}) @@ -3106,16 +3105,14 @@ hash=${hash} get_filename_component(fname "${fname}" NAME) else() # Fall back to a default file name. The actual file name does not - # matter as long as it doesn't conflict with other projects because - # it is used only internally and our extraction tool inspects the - # file content directly. If it turns out the wrong URL was given - # that will be revealed during the build which is an easier place for - # users to diagnose than an error here anyway. - set(fname "${name}-archive.tar") + # matter because it is used only internally and our extraction tool + # inspects the file content directly. If it turns out the wrong URL + # was given that will be revealed during the build which is an easier + # place for users to diagnose than an error here anyway. + set(fname "archive.tar") endif() string(REPLACE ";" "-" fname "${fname}") set(file ${download_dir}/${fname}) - set(byproduct_file "${download_dir}/${fname}") get_property(timeout TARGET ${name} PROPERTY _EP_TIMEOUT) get_property(inactivity_timeout TARGET ${name} @@ -3292,7 +3289,6 @@ hash=${hash} COMMAND ${__cmdQuoted} WORKING_DIRECTORY \${work_dir} DEPENDS \${depends} - BYPRODUCTS \${byproduct_file} DEPENDEES mkdir ${log} ${uses_terminal} diff --git a/Modules/FeatureSummary.cmake b/Modules/FeatureSummary.cmake index 77c66d14a..009ca3895 100644 --- a/Modules/FeatureSummary.cmake +++ b/Modules/FeatureSummary.cmake @@ -17,7 +17,7 @@ packages and/or feature for a build tree such as:: PNG, A PNG image library., * Enables saving screenshots -- The following OPTIONAL packages have not been found: - Lua51, The Lua scripting language., + Lua51, The Lua scripting language., * Enables macros in MyWordProcessor Foo, Foo provides cool stuff. diff --git a/Modules/FindBoost.cmake b/Modules/FindBoost.cmake index 1f82bb52a..248ea8b63 100644 --- a/Modules/FindBoost.cmake +++ b/Modules/FindBoost.cmake @@ -1394,7 +1394,7 @@ function(_Boost_COMPONENT_DEPENDENCIES component _ret) set(_Boost_THREAD_DEPENDENCIES chrono atomic) set(_Boost_WAVE_DEPENDENCIES filesystem serialization thread chrono atomic) set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) - if(Boost_VERSION_STRING VERSION_GREATER_EQUAL 1.84.0 AND NOT Boost_NO_WARN_NEW_VERSIONS) + if(Boost_VERSION_STRING VERSION_GREATER_EQUAL 1.85.0 AND NOT Boost_NO_WARN_NEW_VERSIONS) message(WARNING "New Boost version may have incorrect or missing dependencies and imported targets") endif() endif() @@ -1669,6 +1669,7 @@ else() # _Boost_COMPONENT_HEADERS. See the instructions at the top of # _Boost_COMPONENT_DEPENDENCIES. set(_Boost_KNOWN_VERSIONS ${Boost_ADDITIONAL_VERSIONS} + "1.84.0" "1.84" "1.83.0" "1.83" "1.82.0" "1.82" "1.81.0" "1.81" "1.80.0" "1.80" "1.79.0" "1.79" "1.78.0" "1.78" "1.77.0" "1.77" "1.76.0" "1.76" "1.75.0" "1.75" "1.74.0" "1.74" "1.73.0" "1.73" "1.72.0" "1.72" "1.71.0" "1.71" "1.70.0" "1.70" "1.69.0" "1.69" diff --git a/Modules/FindCUDAToolkit.cmake b/Modules/FindCUDAToolkit.cmake index b4c596c05..469a7adc9 100644 --- a/Modules/FindCUDAToolkit.cmake +++ b/Modules/FindCUDAToolkit.cmake @@ -960,7 +960,7 @@ endif() # the version of the CUDA toolchain # Create a separate variable so this directory can be selectively added to math targets. find_path(CUDAToolkit_CUBLAS_INCLUDE_DIR cublas_v2.h PATHS - "${CUDAToolkit_INCLUDE_DIRECTORIES}" + ${CUDAToolkit_INCLUDE_DIRECTORIES} NO_DEFAULT_PATH) if(NOT CUDAToolkit_CUBLAS_INCLUDE_DIR) @@ -973,7 +973,7 @@ if(NOT CUDAToolkit_CUBLAS_INCLUDE_DIR) cmake_path(NORMAL_PATH CUDAToolkit_MATH_INCLUDE_DIR) find_path(CUDAToolkit_CUBLAS_INCLUDE_DIR cublas_v2.h PATHS - "${CUDAToolkit_INCLUDE_DIRECTORIES}" + ${CUDAToolkit_INCLUDE_DIRECTORIES} ) if(CUDAToolkit_CUBLAS_INCLUDE_DIR) list(APPEND CUDAToolkit_INCLUDE_DIRECTORIES "${CUDAToolkit_CUBLAS_INCLUDE_DIR}") @@ -1246,7 +1246,7 @@ if(CUDAToolkit_FOUND) find_path(CUDAToolkit_CUPTI_INCLUDE_DIR cupti.h PATHS "${CUDAToolkit_ROOT_DIR}/extras/CUPTI/include" - "${CUDAToolkit_INCLUDE_DIRS}" + ${CUDAToolkit_INCLUDE_DIRS} PATH_SUFFIXES "../extras/CUPTI/include" "../../../extras/CUPTI/include" NO_DEFAULT_PATH) diff --git a/Modules/FindFreetype.cmake b/Modules/FindFreetype.cmake index 735276944..82885cb2f 100644 --- a/Modules/FindFreetype.cmake +++ b/Modules/FindFreetype.cmake @@ -65,104 +65,6 @@ directory of a Freetype installation. # I'm going to attempt to cut out the middleman and hope # everything still works. -set(_Freetype_args) -if (Freetype_FIND_VERSION) - list(APPEND _Freetype_args - "${Freetype_FIND_VERSION}") - if (Freetype_FIND_VERSION_EXACT) - list(APPEND _Freetype_args - EXACT) - endif () -endif () -set(_Freetype_component_req) -set(_Freetype_component_opt) -foreach (_Freetype_component IN LISTS Freetype_FIND_COMPONENTS) - if (Freetype_FIND_REQUIRE_${_Freetype_component}) - list(APPEND _Freetype_component_req - "${_Freetype_component}") - else () - list(APPEND _Freetype_component_opt - "${_Freetype_component}") - endif () -endforeach () -unset(_Freetype_component) -if (_Freetype_component_req) - list(APPEND _Freetype_args - COMPONENTS "${_Freetype_component_req}") -endif () -unset(_Freetype_component_req) -if (_Freetype_component_opt) - list(APPEND _Freetype_args - OPTIONAL_COMPONENTS "${_Freetype_component_opt}") -endif () -unset(_Freetype_component_opt) -# Always find with QUIET to avoid noise when it is not found. -find_package(freetype CONFIG QUIET ${_Freetype_args}) -unset(_Freetype_args) -if (freetype_FOUND) - if (NOT TARGET Freetype::Freetype) - add_library(Freetype::Freetype IMPORTED INTERFACE) - set_target_properties(Freetype::Freetype PROPERTIES - INTERFACE_LINK_LIBRARIES freetype) - endif () - get_property(FREETYPE_INCLUDE_DIRS TARGET freetype PROPERTY INTERFACE_INCLUDE_DIRECTORIES) - get_property(FREETYPE_LIBRARIES TARGET freetype PROPERTY INTERFACE_LINK_LIBRARIES) - get_property(_Freetype_location TARGET freetype PROPERTY IMPORTED_IMPLIB) - if (NOT _Freetype_location) - get_property(_Freetype_location_release TARGET freetype PROPERTY IMPORTED_IMPLIB_RELEASE) - if (NOT _Freetype_location_release) - get_property(_Freetype_location_release TARGET freetype PROPERTY IMPORTED_IMPLIB_RELWITHDEBINFO) - endif () - get_property(_Freetype_location_debug TARGET freetype PROPERTY IMPORTED_IMPLIB_DEBUG) - if (_Freetype_location_release AND _Freetype_location_debug) - set(_Freetype_location - optimized "${_Freetype_location_release}" - debug "${_Freetype_location_debug}") - elseif (_Freetype_location_release) - set(_Freetype_location "${_Freetype_location_release}") - elseif (_Freetype_location_debug) - set(_Freetype_location "${_Freetype_location_debug}") - else () - get_property(_Freetype_location_release TARGET freetype PROPERTY LOCATION_RELEASE) - if (NOT _Freetype_location_release) - get_property(_Freetype_location_release TARGET freetype PROPERTY LOCATION_RELWITHDEBINFO) - endif () - get_property(_Freetype_location_debug TARGET freetype PROPERTY LOCATION_DEBUG) - if (_Freetype_location_release AND _Freetype_location_debug) - set(_Freetype_location - optimized "${_Freetype_location_release}" - debug "${_Freetype_location_debug}") - elseif (_Freetype_location_release) - set(_Freetype_location "${_Freetype_location_release}") - elseif (_Freetype_location_debug) - set(_Freetype_location "${_Freetype_location_debug}") - else () - get_property(_Freetype_location TARGET freetype PROPERTY LOCATION) - endif () - endif () - unset(_Freetype_location_release) - unset(_Freetype_location_debug) - endif () - list(INSERT FREETYPE_LIBRARIES 0 - "${_Freetype_location}") - unset(_Freetype_location) - set(Freetype_FOUND 1) - set(FREETYPE_FOUND 1) - set(FREETYPE_VERSION_STRING "${freetype_VERSION}") - foreach (_Freetype_component IN LISTS Freetype_FIND_COMPONENTS) - set(Freetype_${_Freetype_component}_FOUND "${freetype_${_Freetype_component}_FOUND}") - endforeach () - unset(_Freetype_component) - - include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) - find_package_handle_standard_args(Freetype - HANDLE_COMPONENTS - VERSION_VAR FREETYPE_VERSION_STRING - ) - - return () -endif () - set(FREETYPE_FIND_ARGS HINTS ENV FREETYPE_DIR diff --git a/Modules/FindMatlab.cmake b/Modules/FindMatlab.cmake index b90a45fda..18255b64e 100644 --- a/Modules/FindMatlab.cmake +++ b/Modules/FindMatlab.cmake @@ -189,17 +189,13 @@ Cached variables the location of the root of the Matlab installation found. If this value is changed by the user, the result variables are recomputed. -Provided macros -^^^^^^^^^^^^^^^ +Provided commands +^^^^^^^^^^^^^^^^^ :command:`matlab_get_version_from_release_name` - returns the version from the release name + returns the version from the Matlab release name :command:`matlab_get_release_name_from_version` returns the release name from the Matlab version - -Provided functions -^^^^^^^^^^^^^^^^^^ - :command:`matlab_add_mex` adds a target compiling a MEX file. :command:`matlab_add_unit_test` @@ -350,6 +346,11 @@ file(MAKE_DIRECTORY "${_matlab_temporary_folder}") * Output: ``version`` is the version of Matlab (e.g. 23.2.0) Returns the version of Matlab from a release name + + .. note:: + + This command provides correct versions mappings for Matlab but not MCR. + #]=======================================================================] macro(matlab_get_version_from_release_name release_name version_name) @@ -377,33 +378,27 @@ endmacro() * Output: ``release_name`` is the release name (R2023b) Returns the release name from the version of Matlab + + .. note:: + + This command provides correct version mappings for Matlab but not MCR. + #]=======================================================================] -macro(matlab_get_release_name_from_version version release_name) +function(matlab_get_release_name_from_version version release_name) # only the major.minor version is used - string(REGEX MATCH "([0-9]+\\.[0-9]+)" _match ${version}) - if(CMAKE_MATCH_1) - set(short_version ${CMAKE_MATCH_1}) - else() - set(short_version ${version}) - endif() + string(REGEX REPLACE "^([0-9]+\\.[0-9]+).*" "\\1" version "${version}") - set(${release_name} "") foreach(_var IN LISTS MATLAB_VERSIONS_MAPPING) - string(REGEX MATCHALL "(.+)=${short_version}" _matched ${_var}) - if(NOT _matched STREQUAL "") - set(${release_name} ${CMAKE_MATCH_1}) - break() + if(_var MATCHES "(.+)=${version}") + set(${release_name} ${CMAKE_MATCH_1} PARENT_SCOPE) + return() endif() endforeach() - unset(_var) - unset(_matched) - if(${release_name} STREQUAL "") - message(WARNING "[MATLAB] The version ${short_version} is not registered") - endif() + message(WARNING "[MATLAB] The version ${version} is not registered") -endmacro() +endfunction() # extracts all the supported release names (R2022b...) of Matlab @@ -453,9 +448,10 @@ endmacro() are installed. The found versions are returned in `matlab_versions`. Set `win64` to `TRUE` if the 64 bit version of Matlab should be looked for The returned list contains all versions under - ``HKLM\\SOFTWARE\\Mathworks\\MATLAB`` and - ``HKLM\\SOFTWARE\\Mathworks\\MATLAB Runtime`` or an empty list in case an - error occurred (or nothing found). + ``HKLM\\SOFTWARE\\Mathworks\\MATLAB``, + ``HKLM\\SOFTWARE\\Mathworks\\MATLAB Runtime`` and + ``HKLM\\SOFTWARE\\Mathworks\\MATLAB Compiler Runtime`` or an empty list in + case an error occurred (or nothing found). .. note:: @@ -466,7 +462,7 @@ endmacro() function(matlab_extract_all_installed_versions_from_registry win64 matlab_versions) if(NOT CMAKE_HOST_WIN32) - message(FATAL_ERROR "[MATLAB] This macro can only be called by a Windows host") + message(FATAL_ERROR "[MATLAB] This function can only be called by a Windows host") endif() if(${win64} AND CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "64") @@ -485,24 +481,22 @@ function(matlab_extract_all_installed_versions_from_registry win64 matlab_versio ) if(_reg) - - string(REGEX MATCHALL "([0-9]+\\.[0-9]+)" _versions_regex "${_reg}") - - foreach(match IN LISTS _versions_regex) - string(REGEX MATCH "([0-9]+\\.[0-9]+)" current_match "${match}") - - if(NOT CMAKE_MATCH_1) - continue() - endif() - - cmake_host_system_information(RESULT _reg - QUERY WINDOWS_REGISTRY "HKLM/SOFTWARE/Mathworks/${_installation_type}/${CMAKE_MATCH_1}" - VALUE "MATLABROOT" - ) - - _Matlab_VersionInfoXML("${_reg}" _matlab_version_tmp) - if(NOT "${_matlab_version_tmp}" STREQUAL "unknown") - list(APPEND matlabs_from_registry ${_matlab_version_tmp}) + string(REGEX MATCHALL "([0-9]+(\\.[0-9]+)+)" _versions_regex "${_reg}") + + foreach(_match IN LISTS _versions_regex) + if(_match MATCHES "([0-9]+(\\.[0-9]+)+)") + cmake_host_system_information(RESULT _reg + QUERY WINDOWS_REGISTRY "HKLM/SOFTWARE/Mathworks/${_installation_type}/${CMAKE_MATCH_1}" + VALUE "MATLABROOT" + VIEW ${_view} + ) + + _Matlab_VersionInfoXML("${_reg}" _matlab_version_tmp) + if("${_matlab_version_tmp}" STREQUAL "unknown") + list(APPEND matlabs_from_registry ${_match}) + else() + list(APPEND matlabs_from_registry ${_matlab_version_tmp}) + endif() endif() endforeach() @@ -558,42 +552,59 @@ function(matlab_get_all_valid_matlab_roots_from_registry matlab_versions matlab_ # extract_matlab_versions_from_registry_brute_force or # matlab_extract_all_installed_versions_from_registry. + # Mostly the major.minor version is used in Mathworks Windows Registry keys. + # If the patch is not zero, major.minor.patch is used. + list(TRANSFORM matlab_versions REPLACE "^([0-9]+\\.[0-9]+(\\.[1-9][0-9]*)?).*" "\\1") + set(_matlab_roots_list ) # check for Matlab installations foreach(_matlab_current_version IN LISTS matlab_versions) - get_filename_component( - current_MATLAB_ROOT - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MathWorks\\MATLAB\\${_matlab_current_version};MATLABROOT]" - ABSOLUTE) + cmake_host_system_information(RESULT current_MATLAB_ROOT + QUERY WINDOWS_REGISTRY "HKLM/SOFTWARE/Mathworks/MATLAB/${_matlab_current_version}" + VALUE "MATLABROOT" + ) + cmake_path(CONVERT "${current_MATLAB_ROOT}" TO_CMAKE_PATH_LIST current_MATLAB_ROOT) if(IS_DIRECTORY "${current_MATLAB_ROOT}") - list(APPEND _matlab_roots_list "MATLAB" ${_matlab_current_version} ${current_MATLAB_ROOT}) + _Matlab_VersionInfoXML("${current_MATLAB_ROOT}" _matlab_version_tmp) + if("${_matlab_version_tmp}" STREQUAL "unknown") + list(APPEND _matlab_roots_list "MATLAB" ${_matlab_current_version} ${current_MATLAB_ROOT}) + else() + list(APPEND _matlab_roots_list "MATLAB" ${_matlab_version_tmp} ${current_MATLAB_ROOT}) + endif() endif() endforeach() # Check for MCR installations foreach(_matlab_current_version IN LISTS matlab_versions) - get_filename_component( - current_MATLAB_ROOT - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MathWorks\\MATLAB Runtime\\${_matlab_current_version};MATLABROOT]" - ABSOLUTE) + cmake_host_system_information(RESULT current_MATLAB_ROOT + QUERY WINDOWS_REGISTRY "HKLM/SOFTWARE/Mathworks/MATLAB Runtime/${_matlab_current_version}" + VALUE "MATLABROOT" + ) + cmake_path(CONVERT "${current_MATLAB_ROOT}" TO_CMAKE_PATH_LIST current_MATLAB_ROOT) # remove the dot string(REPLACE "." "" _matlab_current_version_without_dot "${_matlab_current_version}") if(IS_DIRECTORY "${current_MATLAB_ROOT}") - list(APPEND _matlab_roots_list "MCR" ${_matlab_current_version} "${current_MATLAB_ROOT}/v${_matlab_current_version_without_dot}") + _Matlab_VersionInfoXML("${current_MATLAB_ROOT}" _matlab_version_tmp) + if("${_matlab_version_tmp}" STREQUAL "unknown") + list(APPEND _matlab_roots_list "MCR" ${_matlab_current_version} "${current_MATLAB_ROOT}/v${_matlab_current_version_without_dot}") + else() + list(APPEND _matlab_roots_list "MCR" ${_matlab_version_tmp} "${current_MATLAB_ROOT}/v${_matlab_current_version_without_dot}") + endif() endif() endforeach() # Check for old MCR installations foreach(_matlab_current_version IN LISTS matlab_versions) - get_filename_component( - current_MATLAB_ROOT - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MathWorks\\MATLAB Compiler Runtime\\${_matlab_current_version};MATLABROOT]" - ABSOLUTE) + cmake_host_system_information(RESULT current_MATLAB_ROOT + QUERY WINDOWS_REGISTRY "HKLM/SOFTWARE/Mathworks/MATLAB Compiler Runtime/${_matlab_current_version}" + VALUE "MATLABROOT" + ) + cmake_path(CONVERT "${current_MATLAB_ROOT}" TO_CMAKE_PATH_LIST current_MATLAB_ROOT) # remove the dot string(REPLACE "." "" _matlab_current_version_without_dot "${_matlab_current_version}") @@ -1409,20 +1420,11 @@ function(_Matlab_VersionInfoXML matlab_root _version) set(_ver "unknown") set(_XMLfile ${matlab_root}/VersionInfo.xml) - if(NOT EXISTS ${_XMLfile}) - return() - endif() - - file(READ ${_XMLfile} versioninfo_string) + if(EXISTS ${_XMLfile}) + file(READ ${_XMLfile} versioninfo_string) - if(versioninfo_string) # parses "23.2.0.2365128" - string(REGEX MATCH "([0-9]+(\\.[0-9]+)+)" - version_reg_match - ${versioninfo_string} - ) - - if(CMAKE_MATCH_1) + if(versioninfo_string MATCHES "([0-9]+(\\.[0-9]+)+)") set(_ver "${CMAKE_MATCH_1}") endif() endif() @@ -1634,7 +1636,17 @@ set(Matlab_VERSION_STRING "NOTFOUND") set(Matlab_Or_MCR "UNKNOWN") if(_numbers_of_matlab_roots GREATER 0) if(Matlab_FIND_VERSION_EXACT) - list(FIND _matlab_possible_roots ${Matlab_FIND_VERSION} _list_index) + set(_list_index -1) + foreach(_matlab_root_index RANGE 1 ${_numbers_of_matlab_roots} 3) + list(GET _matlab_possible_roots ${_matlab_root_index} _matlab_root_version) + # only the major.minor version is used + string(REGEX REPLACE "^([0-9]+\\.[0-9]+).*" "\\1" _matlab_root_version "${_matlab_root_version}") + if(_matlab_root_version VERSION_EQUAL Matlab_FIND_VERSION) + set(_list_index ${_matlab_root_index}) + break() + endif() + endforeach() + if(_list_index LESS 0) set(_list_index 1) endif() diff --git a/Modules/Internal/CMakeCUDAArchitecturesAll.cmake b/Modules/Internal/CMakeCUDAArchitecturesAll.cmake index 873400ae2..c588dfb8d 100644 --- a/Modules/Internal/CMakeCUDAArchitecturesAll.cmake +++ b/Modules/Internal/CMakeCUDAArchitecturesAll.cmake @@ -55,23 +55,25 @@ function(cmake_cuda_architectures_all lang lang_var_) endif() if(${lang_var_}TOOLKIT_VERSION VERSION_GREATER_EQUAL 11.4) - if(CMAKE_${lang}_COMPILER_ID STREQUAL "NVIDIA") + if(CMAKE_${lang}_COMPILER_ID STREQUAL "NVIDIA" + OR (CMAKE_${lang}_COMPILER_ID STREQUAL "Clang" AND CMAKE_${lang}_COMPILER_VERSION VERSION_GREATER_EQUAL 16.0) + ) list(APPEND CMAKE_CUDA_ARCHITECTURES_ALL 87) endif() endif() if(${lang_var_}TOOLKIT_VERSION VERSION_GREATER_EQUAL 11.8) - if(CMAKE_${lang}_COMPILER_ID STREQUAL "NVIDIA") + if(CMAKE_${lang}_COMPILER_ID STREQUAL "NVIDIA" + OR (CMAKE_${lang}_COMPILER_ID STREQUAL "Clang" AND CMAKE_${lang}_COMPILER_VERSION VERSION_GREATER_EQUAL 16.0) + ) list(APPEND CMAKE_CUDA_ARCHITECTURES_ALL 89 90) list(APPEND CMAKE_CUDA_ARCHITECTURES_ALL_MAJOR 90) endif() endif() if(${lang_var_}TOOLKIT_VERSION VERSION_GREATER_EQUAL 12.0) - if(CMAKE_${lang}_COMPILER_ID STREQUAL "NVIDIA") - list(REMOVE_ITEM CMAKE_CUDA_ARCHITECTURES_ALL 35 37) - list(REMOVE_ITEM CMAKE_CUDA_ARCHITECTURES_ALL_MAJOR 35) - endif() + list(REMOVE_ITEM CMAKE_CUDA_ARCHITECTURES_ALL 35 37) + list(REMOVE_ITEM CMAKE_CUDA_ARCHITECTURES_ALL_MAJOR 35) endif() # only generate jit code for the newest arch for all/all-major diff --git a/Modules/UsePkgConfig.cmake b/Modules/UsePkgConfig.cmake index b0202595c..fdf632a1d 100644 --- a/Modules/UsePkgConfig.cmake +++ b/Modules/UsePkgConfig.cmake @@ -41,20 +41,19 @@ macro(PKGCONFIG _package _include_DIR _link_DIR _link_FLAGS _cflags) if(NOT _return_VALUE) execute_process(COMMAND ${PKGCONFIG_EXECUTABLE} ${_package} --variable=includedir - OUTPUT_VARIABLE ${_include_DIR} ) + OUTPUT_VARIABLE ${_include_DIR} OUTPUT_STRIP_TRAILING_WHITESPACE ) string(REGEX REPLACE "[\r\n]" " " ${_include_DIR} "${${_include_DIR}}") - execute_process(COMMAND ${PKGCONFIG_EXECUTABLE} ${_package} --variable=libdir - OUTPUT_VARIABLE ${_link_DIR} ) + OUTPUT_VARIABLE ${_link_DIR} OUTPUT_STRIP_TRAILING_WHITESPACE ) string(REGEX REPLACE "[\r\n]" " " ${_link_DIR} "${${_link_DIR}}") execute_process(COMMAND ${PKGCONFIG_EXECUTABLE} ${_package} --libs - OUTPUT_VARIABLE ${_link_FLAGS} ) + OUTPUT_VARIABLE ${_link_FLAGS} OUTPUT_STRIP_TRAILING_WHITESPACE ) string(REGEX REPLACE "[\r\n]" " " ${_link_FLAGS} "${${_link_FLAGS}}") execute_process(COMMAND ${PKGCONFIG_EXECUTABLE} ${_package} --cflags - OUTPUT_VARIABLE ${_cflags} ) + OUTPUT_VARIABLE ${_cflags} OUTPUT_STRIP_TRAILING_WHITESPACE ) string(REGEX REPLACE "[\r\n]" " " ${_cflags} "${${_cflags}}") else() diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 4c9d32b7e..24f9aac86 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,7 +1,7 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 28) -set(CMake_VERSION_PATCH 1) +set(CMake_VERSION_PATCH 2) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) @@ -21,7 +21,7 @@ endif() if(NOT CMake_VERSION_NO_GIT) # If this source was exported by 'git archive', use its commit info. - set(git_info [==[1eed682d7c CMake 3.28.1]==]) + set(git_info [==[1f25aa1a0a CMake 3.28.2]==]) # Otherwise, try to identify the current development source version. if(NOT git_info MATCHES "^([0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]?[0-9a-f]?)[0-9a-f]* " diff --git a/Source/CPack/cmCPackSTGZGenerator.cxx b/Source/CPack/cmCPackSTGZGenerator.cxx index 1248d171a..6ad375595 100644 --- a/Source/CPack/cmCPackSTGZGenerator.cxx +++ b/Source/CPack/cmCPackSTGZGenerator.cxx @@ -7,8 +7,6 @@ #include #include -#include - #include "cmsys/FStream.hxx" #include "cm_sys_stat.h" diff --git a/Source/CTest/cmCTestBZR.cxx b/Source/CTest/cmCTestBZR.cxx index 36df344ee..246e8117f 100644 --- a/Source/CTest/cmCTestBZR.cxx +++ b/Source/CTest/cmCTestBZR.cxx @@ -135,14 +135,14 @@ private: std::string cmCTestBZR::LoadInfo() { // Run "bzr info" to get the repository info from the work tree. - std::string bzr = this->CommandLineTool; - std::vector bzr_info = { bzr, "info" }; + const char* bzr = this->CommandLineTool.c_str(); + const char* bzr_info[] = { bzr, "info", nullptr }; InfoParser iout(this, "info-out> "); OutputLogger ierr(this->Log, "info-err> "); this->RunChild(bzr_info, &iout, &ierr); // Run "bzr revno" to get the repository revision number from the work tree. - std::vector bzr_revno = { bzr, "revno" }; + const char* bzr_revno[] = { bzr, "revno", nullptr }; std::string rev; RevnoParser rout(this, "revno-out> ", rev); OutputLogger rerr(this->Log, "revno-err> "); @@ -372,18 +372,22 @@ bool cmCTestBZR::UpdateImpl() // TODO: if(this->CTest->GetTestModel() == cmCTest::NIGHTLY) // Use "bzr pull" to update the working tree. - std::vector bzr_update; - bzr_update.push_back(this->CommandLineTool); + std::vector bzr_update; + bzr_update.push_back(this->CommandLineTool.c_str()); bzr_update.push_back("pull"); - cm::append(bzr_update, args); + for (std::string const& arg : args) { + bzr_update.push_back(arg.c_str()); + } + + bzr_update.push_back(this->URL.c_str()); - bzr_update.push_back(this->URL); + bzr_update.push_back(nullptr); // For some reason bzr uses stderr to display the update status. OutputLogger out(this->Log, "pull-out> "); UpdateParser err(this, "pull-err> "); - return this->RunUpdateCommand(bzr_update, &out, &err); + return this->RunUpdateCommand(bzr_update.data(), &out, &err); } bool cmCTestBZR::LoadRevisions() @@ -404,9 +408,10 @@ bool cmCTestBZR::LoadRevisions() } // Run "bzr log" to get all global revisions of interest. - std::string bzr = this->CommandLineTool; - std::vector bzr_log = { bzr, "log", "-v", "-r", - revs, "--xml", this->URL }; + const char* bzr = this->CommandLineTool.c_str(); + const char* bzr_log[] = { + bzr, "log", "-v", "-r", revs.c_str(), "--xml", this->URL.c_str(), nullptr + }; { LogParser out(this, "log-out> "); OutputLogger err(this->Log, "log-err> "); @@ -462,8 +467,8 @@ private: bool cmCTestBZR::LoadModifications() { // Run "bzr status" which reports local modifications. - std::string bzr = this->CommandLineTool; - std::vector bzr_status = { bzr, "status", "-SV" }; + const char* bzr = this->CommandLineTool.c_str(); + const char* bzr_status[] = { bzr, "status", "-SV", nullptr }; StatusParser out(this, "status-out> "); OutputLogger err(this->Log, "status-err> "); this->RunChild(bzr_status, &out, &err); diff --git a/Source/CTest/cmCTestBuildAndTestHandler.cxx b/Source/CTest/cmCTestBuildAndTestHandler.cxx index bb6ccc3f3..5feb95316 100644 --- a/Source/CTest/cmCTestBuildAndTestHandler.cxx +++ b/Source/CTest/cmCTestBuildAndTestHandler.cxx @@ -7,6 +7,8 @@ #include #include +#include "cmsys/Process.h" + #include "cmBuildOptions.h" #include "cmCTest.h" #include "cmCTestTestHandler.h" @@ -306,11 +308,12 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring) return 1; } - std::vector testCommand; - testCommand.push_back(fullPath); + std::vector testCommand; + testCommand.push_back(fullPath.c_str()); for (std::string const& testCommandArg : this->TestCommandArgs) { - testCommand.push_back(testCommandArg); + testCommand.push_back(testCommandArg.c_str()); } + testCommand.push_back(nullptr); std::string outs; int retval = 0; // run the test from the this->BuildRunDir if set @@ -346,10 +349,10 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring) } } - bool runTestRes = this->CTest->RunTest(testCommand, &outs, &retval, nullptr, - remainingTime, nullptr); + int runTestRes = this->CTest->RunTest(testCommand, &outs, &retval, nullptr, + remainingTime, nullptr); - if (!runTestRes || retval != 0) { + if (runTestRes != cmsysProcess_State_Exited || retval != 0) { out << "Test command failed: " << testCommand[0] << "\n"; retval = 1; } diff --git a/Source/CTest/cmCTestBuildHandler.cxx b/Source/CTest/cmCTestBuildHandler.cxx index 859798efd..00ecf42c5 100644 --- a/Source/CTest/cmCTestBuildHandler.cxx +++ b/Source/CTest/cmCTestBuildHandler.cxx @@ -3,17 +3,15 @@ #include "cmCTestBuildHandler.h" #include -#include #include #include #include #include -#include - #include "cmsys/Directory.hxx" #include "cmsys/FStream.hxx" +#include "cmsys/Process.h" #include "cmCTest.h" #include "cmCTestLaunchReporter.h" @@ -26,9 +24,6 @@ #include "cmStringAlgorithms.h" #include "cmStringReplaceHelper.h" #include "cmSystemTools.h" -#include "cmUVHandlePtr.h" -#include "cmUVProcessChain.h" -#include "cmUVStream.h" #include "cmValue.h" #include "cmXMLWriter.h" @@ -425,7 +420,7 @@ int cmCTestBuildHandler::ProcessHandler() cmStringReplaceHelper colorRemover("\x1b\\[[0-9;]*m", "", nullptr); this->ColorRemover = &colorRemover; int retVal = 0; - bool res = true; + int res = cmsysProcess_State_Exited; if (!this->CTest->GetShowOnly()) { res = this->RunMakeCommand(makeCommand, &retVal, buildDirectory.c_str(), 0, ofs); @@ -480,7 +475,7 @@ int cmCTestBuildHandler::ProcessHandler() } this->GenerateXMLFooter(xml, elapsed_build_time); - if (!res || retVal || this->TotalErrors > 0) { + if (res != cmsysProcess_State_Exited || retVal || this->TotalErrors > 0) { cmCTestLog(this->CTest, ERROR_MESSAGE, "Error(s) when building project" << std::endl); } @@ -769,10 +764,10 @@ void cmCTestBuildHandler::LaunchHelper::WriteScrapeMatchers( } } -bool cmCTestBuildHandler::RunMakeCommand(const std::string& command, - int* retVal, const char* dir, - int timeout, std::ostream& ofs, - Encoding encoding) +int cmCTestBuildHandler::RunMakeCommand(const std::string& command, + int* retVal, const char* dir, + int timeout, std::ostream& ofs, + Encoding encoding) { // First generate the command and arguments std::vector args = cmSystemTools::ParseArguments(command); @@ -781,9 +776,19 @@ bool cmCTestBuildHandler::RunMakeCommand(const std::string& command, return false; } + std::vector argv; + argv.reserve(args.size() + 1); + for (std::string const& arg : args) { + argv.push_back(arg.c_str()); + } + argv.push_back(nullptr); + cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Run command:", this->Quiet); - for (auto const& arg : args) { + for (char const* arg : argv) { + if (!arg) { + break; + } cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " \"" << arg << "\"", this->Quiet); } @@ -795,20 +800,21 @@ bool cmCTestBuildHandler::RunMakeCommand(const std::string& command, static_cast(launchHelper); // Now create process object - cmUVProcessChainBuilder builder; - builder.AddCommand(args) - .SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT) - .SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR); - if (dir) { - builder.SetWorkingDirectory(dir); - } - auto chain = builder.Start(); + cmsysProcess* cp = cmsysProcess_New(); + cmsysProcess_SetCommand(cp, argv.data()); + cmsysProcess_SetWorkingDirectory(cp, dir); + cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1); + cmsysProcess_SetTimeout(cp, timeout); + cmsysProcess_Execute(cp); // Initialize tick's std::string::size_type tick = 0; - static constexpr std::string::size_type tick_len = 1024; + const std::string::size_type tick_len = 1024; + char* data; + int length; cmProcessOutput processOutput(encoding); + std::string strdata; cmCTestOptionalLog( this->CTest, HANDLER_PROGRESS_OUTPUT, " Each symbol represents " @@ -830,65 +836,39 @@ bool cmCTestBuildHandler::RunMakeCommand(const std::string& command, this->WarningQuotaReached = false; this->ErrorQuotaReached = false; - cm::uv_timer_ptr timer; - bool timedOut = false; - timer.init(chain.GetLoop(), &timedOut); - if (timeout > 0) { - timer.start( - [](uv_timer_t* t) { - auto* timedOutPtr = static_cast(t->data); - *timedOutPtr = true; - }, - timeout * 1000, 0); - } - // For every chunk of data - cm::uv_pipe_ptr outputStream; - bool outFinished = false; - cm::uv_pipe_ptr errorStream; - bool errFinished = false; - auto startRead = [this, &chain, &processOutput, &tick, - &ofs](cm::uv_pipe_ptr& pipe, int stream, - t_BuildProcessingQueueType& queue, bool& finished, - int id) -> std::unique_ptr { - pipe.init(chain.GetLoop(), 0); - uv_pipe_open(pipe, stream); - return cmUVStreamRead( - pipe, - [this, &processOutput, &queue, id, &tick, &ofs](std::vector data) { - // Replace '\0' with '\n', since '\0' does not really make sense. This - // is for Visual Studio output - for (auto& c : data) { - if (c == 0) { - c = '\n'; - } - } + int res; + while ((res = cmsysProcess_WaitForData(cp, &data, &length, nullptr))) { + // Replace '\0' with '\n', since '\0' does not really make sense. This is + // for Visual Studio output + for (int cc = 0; cc < length; ++cc) { + if (data[cc] == 0) { + data[cc] = '\n'; + } + } - // Process the chunk of data - std::string strdata; - processOutput.DecodeText(data.data(), data.size(), strdata, id); - this->ProcessBuffer(strdata.c_str(), strdata.size(), tick, tick_len, - ofs, &queue); - }, - [this, &processOutput, &queue, id, &tick, &ofs, &finished]() { - std::string strdata; - processOutput.DecodeText(std::string(), strdata, id); - if (!strdata.empty()) { - this->ProcessBuffer(strdata.c_str(), strdata.size(), tick, tick_len, - ofs, &queue); - } - finished = true; - }); - }; - auto outputHandle = startRead(outputStream, chain.OutputStream(), - this->BuildProcessingQueue, outFinished, 1); - auto errorHandle = - startRead(errorStream, chain.ErrorStream(), - this->BuildProcessingErrorQueue, errFinished, 2); - - while (!timedOut && !(outFinished && errFinished && chain.Finished())) { - uv_run(&chain.GetLoop(), UV_RUN_ONCE); + // Process the chunk of data + if (res == cmsysProcess_Pipe_STDERR) { + processOutput.DecodeText(data, length, strdata, 1); + this->ProcessBuffer(strdata.c_str(), strdata.size(), tick, tick_len, ofs, + &this->BuildProcessingErrorQueue); + } else { + processOutput.DecodeText(data, length, strdata, 2); + this->ProcessBuffer(strdata.c_str(), strdata.size(), tick, tick_len, ofs, + &this->BuildProcessingQueue); + } + } + processOutput.DecodeText(std::string(), strdata, 1); + if (!strdata.empty()) { + this->ProcessBuffer(strdata.c_str(), strdata.size(), tick, tick_len, ofs, + &this->BuildProcessingErrorQueue); } + processOutput.DecodeText(std::string(), strdata, 2); + if (!strdata.empty()) { + this->ProcessBuffer(strdata.c_str(), strdata.size(), tick, tick_len, ofs, + &this->BuildProcessingQueue); + } + this->ProcessBuffer(nullptr, 0, tick, tick_len, ofs, &this->BuildProcessingQueue); this->ProcessBuffer(nullptr, 0, tick, tick_len, ofs, @@ -899,93 +879,90 @@ bool cmCTestBuildHandler::RunMakeCommand(const std::string& command, << std::endl, this->Quiet); - if (chain.Finished()) { - auto const& status = chain.GetStatus(0); - auto exception = status.GetException(); - switch (exception.first) { - case cmUVProcessChain::ExceptionCode::None: - if (retVal) { - *retVal = static_cast(status.ExitStatus); - cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, - "Command exited with the value: " << *retVal - << std::endl, - this->Quiet); - // if a non zero return value - if (*retVal) { - // If there was an error running command, report that on the - // dashboard. - if (this->UseCTestLaunch) { - // For launchers, do not record this top-level error if other - // more granular build errors have already been captured. - bool launcherXMLFound = false; - cmsys::Directory launchDir; - launchDir.Load(this->CTestLaunchDir); - unsigned long n = launchDir.GetNumberOfFiles(); - for (unsigned long i = 0; i < n; ++i) { - const char* fname = launchDir.GetFile(i); - if (cmHasLiteralSuffix(fname, ".xml")) { - launcherXMLFound = true; - break; - } - } - if (!launcherXMLFound) { - cmCTestLaunchReporter reporter; - reporter.RealArgs = args; - reporter.ComputeFileNames(); - reporter.ExitCode = *retVal; - reporter.Status = status; - // Use temporary BuildLog file to populate this error for - // CDash. - ofs.flush(); - reporter.LogOut = this->LogFileNames["Build"]; - reporter.LogOut += ".tmp"; - reporter.WriteXML(); - } - } else { - cmCTestBuildErrorWarning errorwarning; - errorwarning.LineNumber = 0; - errorwarning.LogLine = 1; - errorwarning.Text = cmStrCat( - "*** WARNING non-zero return value in ctest from: ", args[0]); - errorwarning.PreContext.clear(); - errorwarning.PostContext.clear(); - errorwarning.Error = false; - this->ErrorsAndWarnings.push_back(std::move(errorwarning)); - this->TotalWarnings++; + // Properly handle output of the build command + cmsysProcess_WaitForExit(cp, nullptr); + int result = cmsysProcess_GetState(cp); + + if (result == cmsysProcess_State_Exited) { + if (retVal) { + *retVal = cmsysProcess_GetExitValue(cp); + cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, + "Command exited with the value: " << *retVal + << std::endl, + this->Quiet); + // if a non zero return value + if (*retVal) { + // If there was an error running command, report that on the + // dashboard. + if (this->UseCTestLaunch) { + // For launchers, do not record this top-level error if other + // more granular build errors have already been captured. + bool launcherXMLFound = false; + cmsys::Directory launchDir; + launchDir.Load(this->CTestLaunchDir); + unsigned long n = launchDir.GetNumberOfFiles(); + for (unsigned long i = 0; i < n; ++i) { + const char* fname = launchDir.GetFile(i); + if (cmHasLiteralSuffix(fname, ".xml")) { + launcherXMLFound = true; + break; } } + if (!launcherXMLFound) { + cmCTestLaunchReporter reporter; + reporter.RealArgs = args; + reporter.ComputeFileNames(); + reporter.ExitCode = *retVal; + reporter.Process = cp; + // Use temporary BuildLog file to populate this error for CDash. + ofs.flush(); + reporter.LogOut = this->LogFileNames["Build"]; + reporter.LogOut += ".tmp"; + reporter.WriteXML(); + } + } else { + cmCTestBuildErrorWarning errorwarning; + errorwarning.LineNumber = 0; + errorwarning.LogLine = 1; + errorwarning.Text = cmStrCat( + "*** WARNING non-zero return value in ctest from: ", argv[0]); + errorwarning.PreContext.clear(); + errorwarning.PostContext.clear(); + errorwarning.Error = false; + this->ErrorsAndWarnings.push_back(std::move(errorwarning)); + this->TotalWarnings++; } - break; - case cmUVProcessChain::ExceptionCode::Spawn: { - // If there was an error running command, report that on the dashboard. - cmCTestBuildErrorWarning errorwarning; - errorwarning.LineNumber = 0; - errorwarning.LogLine = 1; - errorwarning.Text = - cmStrCat("*** ERROR executing: ", exception.second); - errorwarning.PreContext.clear(); - errorwarning.PostContext.clear(); - errorwarning.Error = true; - this->ErrorsAndWarnings.push_back(std::move(errorwarning)); - this->TotalErrors++; - cmCTestLog(this->CTest, ERROR_MESSAGE, - "There was an error: " << exception.second << std::endl); - } break; - default: - if (retVal) { - *retVal = status.TermSignal; - cmCTestOptionalLog( - this->CTest, WARNING, - "There was an exception: " << *retVal << std::endl, this->Quiet); - } - break; + } } - } else { + } else if (result == cmsysProcess_State_Exception) { + if (retVal) { + *retVal = cmsysProcess_GetExitException(cp); + cmCTestOptionalLog(this->CTest, WARNING, + "There was an exception: " << *retVal << std::endl, + this->Quiet); + } + } else if (result == cmsysProcess_State_Expired) { cmCTestOptionalLog(this->CTest, WARNING, "There was a timeout" << std::endl, this->Quiet); + } else if (result == cmsysProcess_State_Error) { + // If there was an error running command, report that on the dashboard. + cmCTestBuildErrorWarning errorwarning; + errorwarning.LineNumber = 0; + errorwarning.LogLine = 1; + errorwarning.Text = + cmStrCat("*** ERROR executing: ", cmsysProcess_GetErrorString(cp)); + errorwarning.PreContext.clear(); + errorwarning.PostContext.clear(); + errorwarning.Error = true; + this->ErrorsAndWarnings.push_back(std::move(errorwarning)); + this->TotalErrors++; + cmCTestLog(this->CTest, ERROR_MESSAGE, + "There was an error: " << cmsysProcess_GetErrorString(cp) + << std::endl); } - return true; + cmsysProcess_Delete(cp); + return result; } // ###################################################################### diff --git a/Source/CTest/cmCTestBuildHandler.h b/Source/CTest/cmCTestBuildHandler.h index 90945b16b..e33294d8f 100644 --- a/Source/CTest/cmCTestBuildHandler.h +++ b/Source/CTest/cmCTestBuildHandler.h @@ -53,9 +53,9 @@ private: //! Run command specialized for make and configure. Returns process status // and retVal is return value or exception. - bool RunMakeCommand(const std::string& command, int* retVal, const char* dir, - int timeout, std::ostream& ofs, - Encoding encoding = cmProcessOutput::Auto); + int RunMakeCommand(const std::string& command, int* retVal, const char* dir, + int timeout, std::ostream& ofs, + Encoding encoding = cmProcessOutput::Auto); enum { diff --git a/Source/CTest/cmCTestCVS.cxx b/Source/CTest/cmCTestCVS.cxx index ef95b2558..95e898cf8 100644 --- a/Source/CTest/cmCTestCVS.cxx +++ b/Source/CTest/cmCTestCVS.cxx @@ -5,7 +5,6 @@ #include #include -#include #include "cmsys/FStream.hxx" #include "cmsys/RegularExpression.hxx" @@ -90,15 +89,18 @@ bool cmCTestCVS::UpdateImpl() } // Run "cvs update" to update the work tree. - std::vector cvs_update; - cvs_update.push_back(this->CommandLineTool); + std::vector cvs_update; + cvs_update.push_back(this->CommandLineTool.c_str()); cvs_update.push_back("-z3"); cvs_update.push_back("update"); - cm::append(cvs_update, args); + for (std::string const& arg : args) { + cvs_update.push_back(arg.c_str()); + } + cvs_update.push_back(nullptr); UpdateParser out(this, "up-out> "); UpdateParser err(this, "up-err> "); - return this->RunUpdateCommand(cvs_update, &out, &err); + return this->RunUpdateCommand(cvs_update.data(), &out, &err); } class cmCTestCVS::LogParser : public cmCTestVC::LineParser @@ -219,8 +221,10 @@ void cmCTestCVS::LoadRevisions(std::string const& file, const char* branchFlag, cmCTestLog(this->CTest, HANDLER_OUTPUT, "." << std::flush); // Run "cvs log" to get revisions of this file on this branch. - std::string cvs = this->CommandLineTool; - std::vector cvs_log = { cvs, "log", "-N", branchFlag, file }; + const char* cvs = this->CommandLineTool.c_str(); + const char* cvs_log[] = { + cvs, "log", "-N", branchFlag, file.c_str(), nullptr + }; LogParser out(this, "log-out> ", revisions); OutputLogger err(this->Log, "log-err> "); diff --git a/Source/CTest/cmCTestConfigureHandler.cxx b/Source/CTest/cmCTestConfigureHandler.cxx index dd8952f2b..914930e00 100644 --- a/Source/CTest/cmCTestConfigureHandler.cxx +++ b/Source/CTest/cmCTestConfigureHandler.cxx @@ -45,7 +45,7 @@ int cmCTestConfigureHandler::ProcessHandler() auto elapsed_time_start = std::chrono::steady_clock::now(); std::string output; int retVal = 0; - bool res = false; + int res = 0; if (!this->CTest->GetShowOnly()) { cmGeneratedFileStream os; if (!this->StartResultingXML(cmCTest::PartConfigure, "Configure", os)) { diff --git a/Source/CTest/cmCTestCoverageHandler.cxx b/Source/CTest/cmCTestCoverageHandler.cxx index 1aa49cf11..2874be7dc 100644 --- a/Source/CTest/cmCTestCoverageHandler.cxx +++ b/Source/CTest/cmCTestCoverageHandler.cxx @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -19,10 +18,9 @@ #include "cmsys/FStream.hxx" #include "cmsys/Glob.hxx" +#include "cmsys/Process.h" #include "cmsys/RegularExpression.hxx" -#include "cm_fileno.hxx" - #include "cmCTest.h" #include "cmDuration.h" #include "cmGeneratedFileStream.h" @@ -35,7 +33,6 @@ #include "cmParsePHPCoverage.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" -#include "cmUVProcessChain.h" #include "cmWorkingDirectory.h" #include "cmXMLWriter.h" @@ -43,6 +40,85 @@ class cmMakefile; #define SAFEDIV(x, y) (((y) != 0) ? ((x) / (y)) : (0)) +class cmCTestRunProcess +{ +public: + cmCTestRunProcess() + { + this->Process = cmsysProcess_New(); + this->PipeState = -1; + this->TimeOut = cmDuration(-1); + } + ~cmCTestRunProcess() + { + if (this->PipeState != -1 && this->PipeState != cmsysProcess_Pipe_None && + this->PipeState != cmsysProcess_Pipe_Timeout) { + this->WaitForExit(); + } + cmsysProcess_Delete(this->Process); + } + cmCTestRunProcess(const cmCTestRunProcess&) = delete; + cmCTestRunProcess& operator=(const cmCTestRunProcess&) = delete; + void SetCommand(const char* command) + { + this->CommandLineStrings.clear(); + this->CommandLineStrings.emplace_back(command); + } + void AddArgument(const char* arg) + { + if (arg) { + this->CommandLineStrings.emplace_back(arg); + } + } + void SetWorkingDirectory(const char* dir) { this->WorkingDirectory = dir; } + void SetTimeout(cmDuration t) { this->TimeOut = t; } + bool StartProcess() + { + std::vector args; + args.reserve(this->CommandLineStrings.size()); + for (std::string const& cl : this->CommandLineStrings) { + args.push_back(cl.c_str()); + } + args.push_back(nullptr); // null terminate + cmsysProcess_SetCommand(this->Process, args.data()); + if (!this->WorkingDirectory.empty()) { + cmsysProcess_SetWorkingDirectory(this->Process, + this->WorkingDirectory.c_str()); + } + + cmsysProcess_SetOption(this->Process, cmsysProcess_Option_HideWindow, 1); + if (this->TimeOut >= cmDuration::zero()) { + cmsysProcess_SetTimeout(this->Process, this->TimeOut.count()); + } + cmsysProcess_Execute(this->Process); + this->PipeState = cmsysProcess_GetState(this->Process); + // if the process is running or exited return true + return this->PipeState == cmsysProcess_State_Executing || + this->PipeState == cmsysProcess_State_Exited; + } + void SetStdoutFile(const char* fname) + { + cmsysProcess_SetPipeFile(this->Process, cmsysProcess_Pipe_STDOUT, fname); + } + void SetStderrFile(const char* fname) + { + cmsysProcess_SetPipeFile(this->Process, cmsysProcess_Pipe_STDERR, fname); + } + int WaitForExit(double* timeout = nullptr) + { + this->PipeState = cmsysProcess_WaitForExit(this->Process, timeout); + return this->PipeState; + } + int GetProcessState() const { return this->PipeState; } + +private: + int PipeState; + cmsysProcess* Process; + std::vector CommandLineStrings; + std::string WorkingDirectory; + cmDuration TimeOut; +}; + cmCTestCoverageHandler::cmCTestCoverageHandler() = default; void cmCTestCoverageHandler::Initialize() @@ -1864,35 +1940,34 @@ int cmCTestCoverageHandler::RunBullseyeCommand( cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot find :" << cmd << "\n"); return 0; } - std::vector args{ cmd }; if (arg) { cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Run : " << program << " " << arg << "\n", this->Quiet); - args.emplace_back(arg); } else { cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Run : " << program << "\n", this->Quiet); } // create a process object and start it - cmUVProcessChainBuilder builder; + cmCTestRunProcess runCoverageSrc; + runCoverageSrc.SetCommand(program.c_str()); + runCoverageSrc.AddArgument(arg); std::string stdoutFile = cmStrCat(cont->BinaryDir, "/Testing/Temporary/", this->GetCTestInstance()->GetCurrentTag(), '-', cmd); std::string stderrFile = stdoutFile; stdoutFile += ".stdout"; stderrFile += ".stderr"; - std::unique_ptr stdoutHandle( - cmsys::SystemTools::Fopen(stdoutFile, "w"), fclose); - std::unique_ptr stderrHandle( - cmsys::SystemTools::Fopen(stderrFile, "w"), fclose); - builder.AddCommand(args) - .SetExternalStream(cmUVProcessChainBuilder::Stream_OUTPUT, - cm_fileno(stdoutHandle.get())) - .SetExternalStream(cmUVProcessChainBuilder::Stream_ERROR, - cm_fileno(stderrHandle.get())); + runCoverageSrc.SetStdoutFile(stdoutFile.c_str()); + runCoverageSrc.SetStderrFile(stderrFile.c_str()); + if (!runCoverageSrc.StartProcess()) { + cmCTestLog(this->CTest, ERROR_MESSAGE, + "Could not run : " << program << " " << arg << "\n" + << "kwsys process state : " + << runCoverageSrc.GetProcessState()); + return 0; + } // since we set the output file names wait for it to end - auto chain = builder.Start(); - chain.Wait(); + runCoverageSrc.WaitForExit(); outputFile = stdoutFile; return 1; } diff --git a/Source/CTest/cmCTestGIT.cxx b/Source/CTest/cmCTestGIT.cxx index ca8659e20..5f8cb7415 100644 --- a/Source/CTest/cmCTestGIT.cxx +++ b/Source/CTest/cmCTestGIT.cxx @@ -9,9 +9,8 @@ #include #include -#include - #include "cmsys/FStream.hxx" +#include "cmsys/Process.h" #include "cmCTest.h" #include "cmCTestVC.h" @@ -19,7 +18,6 @@ #include "cmProcessOutput.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" -#include "cmUVProcessChain.h" #include "cmValue.h" static unsigned int cmCTestGITVersion(unsigned int epic, unsigned int major, @@ -60,9 +58,9 @@ private: std::string cmCTestGIT::GetWorkingRevision() { // Run plumbing "git rev-list" to get work tree revision. - std::string git = this->CommandLineTool; - std::vector git_rev_list = { git, "rev-list", "-n", - "1", "HEAD", "--" }; + const char* git = this->CommandLineTool.c_str(); + const char* git_rev_list[] = { git, "rev-list", "-n", "1", + "HEAD", "--", nullptr }; std::string rev; OneLineParser out(this, "rl-out> ", rev); OutputLogger err(this->Log, "rl-err> "); @@ -94,13 +92,13 @@ std::string cmCTestGIT::FindGitDir() std::string git_dir; // Run "git rev-parse --git-dir" to locate the real .git directory. - std::string git = this->CommandLineTool; - std::vector git_rev_parse = { git, "rev-parse", "--git-dir" }; + const char* git = this->CommandLineTool.c_str(); + char const* git_rev_parse[] = { git, "rev-parse", "--git-dir", nullptr }; std::string git_dir_line; OneLineParser rev_parse_out(this, "rev-parse-out> ", git_dir_line); OutputLogger rev_parse_err(this->Log, "rev-parse-err> "); - if (this->RunChild(git_rev_parse, &rev_parse_out, &rev_parse_err, - std::string{}, cmProcessOutput::UTF8)) { + if (this->RunChild(git_rev_parse, &rev_parse_out, &rev_parse_err, nullptr, + cmProcessOutput::UTF8)) { git_dir = git_dir_line; } if (git_dir.empty()) { @@ -119,10 +117,11 @@ std::string cmCTestGIT::FindGitDir() std::string cygpath_exe = cmStrCat(cmSystemTools::GetFilenamePath(git), "/cygpath.exe"); if (cmSystemTools::FileExists(cygpath_exe)) { - std::vector cygpath = { cygpath_exe, "-w", git_dir }; + char const* cygpath[] = { cygpath_exe.c_str(), "-w", git_dir.c_str(), + 0 }; OneLineParser cygpath_out(this, "cygpath-out> ", git_dir_line); OutputLogger cygpath_err(this->Log, "cygpath-err> "); - if (this->RunChild(cygpath, &cygpath_out, &cygpath_err, std::string{}, + if (this->RunChild(cygpath, &cygpath_out, &cygpath_err, nullptr, cmProcessOutput::UTF8)) { git_dir = git_dir_line; } @@ -137,12 +136,12 @@ std::string cmCTestGIT::FindTopDir() std::string top_dir = this->SourceDirectory; // Run "git rev-parse --show-cdup" to locate the top of the tree. - std::string git = this->CommandLineTool; - std::vector git_rev_parse = { git, "rev-parse", "--show-cdup" }; + const char* git = this->CommandLineTool.c_str(); + char const* git_rev_parse[] = { git, "rev-parse", "--show-cdup", nullptr }; std::string cdup; OneLineParser rev_parse_out(this, "rev-parse-out> ", cdup); OutputLogger rev_parse_err(this->Log, "rev-parse-err> "); - if (this->RunChild(git_rev_parse, &rev_parse_out, &rev_parse_err, "", + if (this->RunChild(git_rev_parse, &rev_parse_out, &rev_parse_err, nullptr, cmProcessOutput::UTF8) && !cdup.empty()) { top_dir += "/"; @@ -154,10 +153,10 @@ std::string cmCTestGIT::FindTopDir() bool cmCTestGIT::UpdateByFetchAndReset() { - std::string git = this->CommandLineTool; + const char* git = this->CommandLineTool.c_str(); // Use "git fetch" to get remote commits. - std::vector git_fetch; + std::vector git_fetch; git_fetch.push_back(git); git_fetch.push_back("fetch"); @@ -167,12 +166,17 @@ bool cmCTestGIT::UpdateByFetchAndReset() opts = this->CTest->GetCTestConfiguration("GITUpdateOptions"); } std::vector args = cmSystemTools::ParseArguments(opts); - cm::append(git_fetch, args); + for (std::string const& arg : args) { + git_fetch.push_back(arg.c_str()); + } + + // Sentinel argument. + git_fetch.push_back(nullptr); // Fetch upstream refs. OutputLogger fetch_out(this->Log, "fetch-out> "); OutputLogger fetch_err(this->Log, "fetch-err> "); - if (!this->RunUpdateCommand(git_fetch, &fetch_out, &fetch_err)) { + if (!this->RunUpdateCommand(git_fetch.data(), &fetch_out, &fetch_err)) { return false; } @@ -203,22 +207,25 @@ bool cmCTestGIT::UpdateByFetchAndReset() } // Reset the local branch to point at that tracked from upstream. - std::vector git_reset = { git, "reset", "--hard", sha1 }; + char const* git_reset[] = { git, "reset", "--hard", sha1.c_str(), nullptr }; OutputLogger reset_out(this->Log, "reset-out> "); OutputLogger reset_err(this->Log, "reset-err> "); - return this->RunChild(git_reset, &reset_out, &reset_err); + return this->RunChild(&git_reset[0], &reset_out, &reset_err); } bool cmCTestGIT::UpdateByCustom(std::string const& custom) { cmList git_custom_command{ custom, cmList::EmptyElements::Yes }; - std::vector git_custom; - git_custom.reserve(git_custom_command.size()); - cm::append(git_custom, git_custom_command); + std::vector git_custom; + git_custom.reserve(git_custom_command.size() + 1); + for (std::string const& i : git_custom_command) { + git_custom.push_back(i.c_str()); + } + git_custom.push_back(nullptr); OutputLogger custom_out(this->Log, "custom-out> "); OutputLogger custom_err(this->Log, "custom-err> "); - return this->RunUpdateCommand(git_custom, &custom_out, &custom_err); + return this->RunUpdateCommand(git_custom.data(), &custom_out, &custom_err); } bool cmCTestGIT::UpdateInternal() @@ -237,14 +244,13 @@ bool cmCTestGIT::UpdateImpl() } std::string top_dir = this->FindTopDir(); - std::string git = this->CommandLineTool; - std::string recursive = "--recursive"; - std::string sync_recursive = "--recursive"; + const char* git = this->CommandLineTool.c_str(); + const char* recursive = "--recursive"; + const char* sync_recursive = "--recursive"; // Git < 1.6.5 did not support submodule --recursive - bool support_recursive = true; if (this->GetGitVersion() < cmCTestGITVersion(1, 6, 5, 0)) { - support_recursive = false; + recursive = nullptr; // No need to require >= 1.6.5 if there are no submodules. if (cmSystemTools::FileExists(top_dir + "/.gitmodules")) { this->Log << "Git < 1.6.5 cannot update submodules recursively\n"; @@ -252,9 +258,8 @@ bool cmCTestGIT::UpdateImpl() } // Git < 1.8.1 did not support sync --recursive - bool support_sync_recursive = true; if (this->GetGitVersion() < cmCTestGITVersion(1, 8, 1, 0)) { - support_sync_recursive = false; + sync_recursive = nullptr; // No need to require >= 1.8.1 if there are no submodules. if (cmSystemTools::FileExists(top_dir + "/.gitmodules")) { this->Log << "Git < 1.8.1 cannot synchronize submodules recursively\n"; @@ -269,39 +274,35 @@ bool cmCTestGIT::UpdateImpl() std::string init_submodules = this->CTest->GetCTestConfiguration("GITInitSubmodules"); if (cmIsOn(init_submodules)) { - std::vector git_submodule_init = { git, "submodule", "init" }; + char const* git_submodule_init[] = { git, "submodule", "init", nullptr }; ret = this->RunChild(git_submodule_init, &submodule_out, &submodule_err, - top_dir); + top_dir.c_str()); if (!ret) { return false; } } - std::vector git_submodule_sync = { git, "submodule", "sync" }; - if (support_sync_recursive) { - git_submodule_sync.push_back(sync_recursive); - } + char const* git_submodule_sync[] = { git, "submodule", "sync", + sync_recursive, nullptr }; ret = this->RunChild(git_submodule_sync, &submodule_out, &submodule_err, - top_dir); + top_dir.c_str()); if (!ret) { return false; } - std::vector git_submodule = { git, "submodule", "update" }; - if (support_recursive) { - git_submodule.push_back(recursive); - } + char const* git_submodule[] = { git, "submodule", "update", recursive, + nullptr }; return this->RunChild(git_submodule, &submodule_out, &submodule_err, - top_dir); + top_dir.c_str()); } unsigned int cmCTestGIT::GetGitVersion() { if (!this->CurrentGitVersion) { - std::string git = this->CommandLineTool; - std::vector git_version = { git, "--version" }; + const char* git = this->CommandLineTool.c_str(); + char const* git_version[] = { git, "--version", nullptr }; std::string version; OneLineParser version_out(this, "version-out> ", version); OutputLogger version_err(this->Log, "version-err> "); @@ -604,49 +605,50 @@ bool cmCTestGIT::LoadRevisions() { // Use 'git rev-list ... | git diff-tree ...' to get revisions. std::string range = this->OldRevision + ".." + this->NewRevision; - std::string git = this->CommandLineTool; - std::vector git_rev_list = { git, "rev-list", "--reverse", - range, "--" }; - std::vector git_diff_tree = { - git, "diff-tree", "--stdin", "--always", - "-z", "-r", "--pretty=raw", "--encoding=utf-8" + const char* git = this->CommandLineTool.c_str(); + const char* git_rev_list[] = { git, "rev-list", "--reverse", + range.c_str(), "--", nullptr }; + const char* git_diff_tree[] = { + git, "diff-tree", "--stdin", "--always", "-z", + "-r", "--pretty=raw", "--encoding=utf-8", nullptr }; this->Log << cmCTestGIT::ComputeCommandLine(git_rev_list) << " | " << cmCTestGIT::ComputeCommandLine(git_diff_tree) << "\n"; - cmUVProcessChainBuilder builder; - builder.AddCommand(git_rev_list) - .AddCommand(git_diff_tree) - .SetWorkingDirectory(this->SourceDirectory); + cmsysProcess* cp = cmsysProcess_New(); + cmsysProcess_AddCommand(cp, git_rev_list); + cmsysProcess_AddCommand(cp, git_diff_tree); + cmsysProcess_SetWorkingDirectory(cp, this->SourceDirectory.c_str()); CommitParser out(this, "dt-out> "); OutputLogger err(this->Log, "dt-err> "); - cmCTestGIT::RunProcess(builder, &out, &err, cmProcessOutput::UTF8); + cmCTestGIT::RunProcess(cp, &out, &err, cmProcessOutput::UTF8); // Send one extra zero-byte to terminate the last record. out.Process("", 1); + cmsysProcess_Delete(cp); return true; } bool cmCTestGIT::LoadModifications() { - std::string git = this->CommandLineTool; + const char* git = this->CommandLineTool.c_str(); // Use 'git update-index' to refresh the index w.r.t. the work tree. - std::vector git_update_index = { git, "update-index", - "--refresh" }; + const char* git_update_index[] = { git, "update-index", "--refresh", + nullptr }; OutputLogger ui_out(this->Log, "ui-out> "); OutputLogger ui_err(this->Log, "ui-err> "); - this->RunChild(git_update_index, &ui_out, &ui_err, "", + this->RunChild(git_update_index, &ui_out, &ui_err, nullptr, cmProcessOutput::UTF8); // Use 'git diff-index' to get modified files. - std::vector git_diff_index = { git, "diff-index", "-z", "HEAD", - "--" }; + const char* git_diff_index[] = { git, "diff-index", "-z", + "HEAD", "--", nullptr }; DiffParser out(this, "di-out> "); OutputLogger err(this->Log, "di-err> "); - this->RunChild(git_diff_index, &out, &err, "", cmProcessOutput::UTF8); + this->RunChild(git_diff_index, &out, &err, nullptr, cmProcessOutput::UTF8); for (Change const& c : out.Changes) { this->DoModification(PathModified, c.Path); diff --git a/Source/CTest/cmCTestHG.cxx b/Source/CTest/cmCTestHG.cxx index e1a945d2a..02837ba9d 100644 --- a/Source/CTest/cmCTestHG.cxx +++ b/Source/CTest/cmCTestHG.cxx @@ -95,8 +95,8 @@ private: std::string cmCTestHG::GetWorkingRevision() { // Run plumbing "hg identify" to get work tree revision. - std::string hg = this->CommandLineTool; - std::vector hg_identify = { hg, "identify", "-i" }; + const char* hg = this->CommandLineTool.c_str(); + const char* hg_identify[] = { hg, "identify", "-i", nullptr }; std::string rev; IdentifyParser out(this, "rev-out> ", rev); OutputLogger err(this->Log, "rev-err> "); @@ -127,16 +127,16 @@ bool cmCTestHG::UpdateImpl() { // Use "hg pull" followed by "hg update" to update the working tree. { - std::string hg = this->CommandLineTool; - std::vector hg_pull = { hg, "pull", "-v" }; + const char* hg = this->CommandLineTool.c_str(); + const char* hg_pull[] = { hg, "pull", "-v", nullptr }; OutputLogger out(this->Log, "pull-out> "); OutputLogger err(this->Log, "pull-err> "); - this->RunChild(hg_pull, &out, &err); + this->RunChild(&hg_pull[0], &out, &err); } // TODO: if(this->CTest->GetTestModel() == cmCTest::NIGHTLY) - std::vector hg_update; + std::vector hg_update; hg_update.push_back(this->CommandLineTool.c_str()); hg_update.push_back("update"); hg_update.push_back("-v"); @@ -147,11 +147,16 @@ bool cmCTestHG::UpdateImpl() opts = this->CTest->GetCTestConfiguration("HGUpdateOptions"); } std::vector args = cmSystemTools::ParseArguments(opts); - cm::append(hg_update, args); + for (std::string const& arg : args) { + hg_update.push_back(arg.c_str()); + } + + // Sentinel argument. + hg_update.push_back(nullptr); OutputLogger out(this->Log, "update-out> "); OutputLogger err(this->Log, "update-err> "); - return this->RunUpdateCommand(hg_update, &out, &err); + return this->RunUpdateCommand(hg_update.data(), &out, &err); } class cmCTestHG::LogParser @@ -272,8 +277,8 @@ bool cmCTestHG::LoadRevisions() // the project has spaces in the path. Also, they may not have // proper XML escapes. std::string range = this->OldRevision + ":" + this->NewRevision; - std::string hg = this->CommandLineTool; - std::string hgXMLTemplate = "CommandLineTool.c_str(); + const char* hgXMLTemplate = "\n" " {author|person}\n" " {author|email}\n" @@ -283,8 +288,10 @@ bool cmCTestHG::LoadRevisions() " {file_adds}\n" " {file_dels}\n" "\n"; - std::vector hg_log = { hg, "log", "--removed", "-r", - range, "--template", hgXMLTemplate }; + const char* hg_log[] = { + hg, "log", "--removed", "-r", range.c_str(), + "--template", hgXMLTemplate, nullptr + }; LogParser out(this, "log-out> "); out.Process("\n" @@ -298,8 +305,8 @@ bool cmCTestHG::LoadRevisions() bool cmCTestHG::LoadModifications() { // Use 'hg status' to get modified files. - std::string hg = this->CommandLineTool; - std::vector hg_status = { hg, "status" }; + const char* hg = this->CommandLineTool.c_str(); + const char* hg_status[] = { hg, "status", nullptr }; StatusParser out(this, "status-out> "); OutputLogger err(this->Log, "status-err> "); this->RunChild(hg_status, &out, &err); diff --git a/Source/CTest/cmCTestLaunch.cxx b/Source/CTest/cmCTestLaunch.cxx index 6b13ad1a1..4a33869fd 100644 --- a/Source/CTest/cmCTestLaunch.cxx +++ b/Source/CTest/cmCTestLaunch.cxx @@ -2,19 +2,13 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmCTestLaunch.h" -#include #include #include -#include -#include - -#include #include "cmsys/FStream.hxx" +#include "cmsys/Process.h" #include "cmsys/RegularExpression.hxx" -#include "cm_fileno.hxx" - #include "cmCTestLaunchReporter.h" #include "cmGlobalGenerator.h" #include "cmMakefile.h" @@ -23,9 +17,6 @@ #include "cmStateSnapshot.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" -#include "cmUVHandlePtr.h" -#include "cmUVProcessChain.h" -#include "cmUVStream.h" #include "cmake.h" #ifdef _WIN32 @@ -37,6 +28,8 @@ cmCTestLaunch::cmCTestLaunch(int argc, const char* const* argv) { + this->Process = nullptr; + if (!this->ParseArguments(argc, argv)) { return; } @@ -47,9 +40,13 @@ cmCTestLaunch::cmCTestLaunch(int argc, const char* const* argv) this->ScrapeRulesLoaded = false; this->HaveOut = false; this->HaveErr = false; + this->Process = cmsysProcess_New(); } -cmCTestLaunch::~cmCTestLaunch() = default; +cmCTestLaunch::~cmCTestLaunch() +{ + cmsysProcess_Delete(this->Process); +} bool cmCTestLaunch::ParseArguments(int argc, const char* const* argv) { @@ -116,12 +113,15 @@ bool cmCTestLaunch::ParseArguments(int argc, const char* const* argv) // Extract the real command line. if (arg0) { - for (int i = 0; i < argc - arg0; ++i) { - this->RealArgV.emplace_back((argv + arg0)[i]); - this->HandleRealArg((argv + arg0)[i]); + this->RealArgC = argc - arg0; + this->RealArgV = argv + arg0; + for (int i = 0; i < this->RealArgC; ++i) { + this->HandleRealArg(this->RealArgV[i]); } return true; } + this->RealArgC = 0; + this->RealArgV = nullptr; std::cerr << "No launch/command separator ('--') found!\n"; return false; } @@ -151,22 +151,17 @@ void cmCTestLaunch::RunChild() } // Prepare to run the real command. - cmUVProcessChainBuilder builder; - builder.AddCommand(this->RealArgV); + cmsysProcess* cp = this->Process; + cmsysProcess_SetCommand(cp, this->RealArgV); cmsys::ofstream fout; cmsys::ofstream ferr; if (this->Reporter.Passthru) { // In passthru mode we just share the output pipes. - builder - .SetExternalStream(cmUVProcessChainBuilder::Stream_OUTPUT, - cm_fileno(stdout)) - .SetExternalStream(cmUVProcessChainBuilder::Stream_ERROR, - cm_fileno(stderr)); + cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDOUT, 1); + cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDERR, 1); } else { // In full mode we record the child output pipes to log files. - builder.SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT) - .SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR); fout.open(this->Reporter.LogOut.c_str(), std::ios::out | std::ios::binary); ferr.open(this->Reporter.LogErr.c_str(), std::ios::out | std::ios::binary); } @@ -179,65 +174,51 @@ void cmCTestLaunch::RunChild() #endif // Run the real command. - auto chain = builder.Start(); + cmsysProcess_Execute(cp); // Record child stdout and stderr if necessary. - cm::uv_pipe_ptr outPipe; - cm::uv_pipe_ptr errPipe; - bool outFinished = true; - bool errFinished = true; - cmProcessOutput processOutput; - std::unique_ptr outputHandle; - std::unique_ptr errorHandle; if (!this->Reporter.Passthru) { - auto beginRead = [&chain, &processOutput]( - cm::uv_pipe_ptr& pipe, int stream, std::ostream& out, - cmsys::ofstream& file, bool& haveData, bool& finished, - int id) -> std::unique_ptr { - pipe.init(chain.GetLoop(), 0); - uv_pipe_open(pipe, stream); - finished = false; - return cmUVStreamRead( - pipe, - [&processOutput, &out, &file, id, &haveData](std::vector data) { - std::string strdata; - processOutput.DecodeText(data.data(), data.size(), strdata, id); - file.write(strdata.c_str(), strdata.size()); - out.write(strdata.c_str(), strdata.size()); - haveData = true; - }, - [&processOutput, &out, &file, &finished, id]() { - std::string strdata; - processOutput.DecodeText(std::string(), strdata, id); - if (!strdata.empty()) { - file.write(strdata.c_str(), strdata.size()); - out.write(strdata.c_str(), strdata.size()); - } - finished = true; - }); - }; - outputHandle = beginRead(outPipe, chain.OutputStream(), std::cout, fout, - this->HaveOut, outFinished, 1); - errorHandle = beginRead(errPipe, chain.ErrorStream(), std::cerr, ferr, - this->HaveErr, errFinished, 2); + char* data = nullptr; + int length = 0; + cmProcessOutput processOutput; + std::string strdata; + while (int p = cmsysProcess_WaitForData(cp, &data, &length, nullptr)) { + if (p == cmsysProcess_Pipe_STDOUT) { + processOutput.DecodeText(data, length, strdata, 1); + fout.write(strdata.c_str(), strdata.size()); + std::cout.write(strdata.c_str(), strdata.size()); + this->HaveOut = true; + } else if (p == cmsysProcess_Pipe_STDERR) { + processOutput.DecodeText(data, length, strdata, 2); + ferr.write(strdata.c_str(), strdata.size()); + std::cerr.write(strdata.c_str(), strdata.size()); + this->HaveErr = true; + } + } + processOutput.DecodeText(std::string(), strdata, 1); + if (!strdata.empty()) { + fout.write(strdata.c_str(), strdata.size()); + std::cout.write(strdata.c_str(), strdata.size()); + } + processOutput.DecodeText(std::string(), strdata, 2); + if (!strdata.empty()) { + ferr.write(strdata.c_str(), strdata.size()); + std::cerr.write(strdata.c_str(), strdata.size()); + } } // Wait for the real command to finish. - while (!(chain.Finished() && outFinished && errFinished)) { - uv_run(&chain.GetLoop(), UV_RUN_ONCE); - } - this->Reporter.Status = chain.GetStatus(0); - if (this->Reporter.Status.GetException().first == - cmUVProcessChain::ExceptionCode::Spawn) { - this->Reporter.ExitCode = 1; - } else { - this->Reporter.ExitCode = - static_cast(this->Reporter.Status.ExitStatus); - } + cmsysProcess_WaitForExit(cp, nullptr); + this->Reporter.ExitCode = cmsysProcess_GetExitValue(cp); } int cmCTestLaunch::Run() { + if (!this->Process) { + std::cerr << "Could not allocate cmsysProcess instance!\n"; + return -1; + } + this->RunChild(); if (this->CheckResults()) { @@ -245,6 +226,7 @@ int cmCTestLaunch::Run() } this->LoadConfig(); + this->Reporter.Process = this->Process; this->Reporter.WriteXML(); return this->Reporter.ExitCode; diff --git a/Source/CTest/cmCTestLaunch.h b/Source/CTest/cmCTestLaunch.h index ef21a26cc..c5a64767c 100644 --- a/Source/CTest/cmCTestLaunch.h +++ b/Source/CTest/cmCTestLaunch.h @@ -43,12 +43,15 @@ private: bool ParseArguments(int argc, const char* const* argv); // The real command line appearing after launcher arguments. - std::vector RealArgV; + int RealArgC; + const char* const* RealArgV; // The real command line after response file expansion. std::vector RealArgs; void HandleRealArg(const char* arg); + struct cmsysProcess_s* Process; + // Whether or not any data have been written to stdout or stderr. bool HaveOut; bool HaveErr; diff --git a/Source/CTest/cmCTestLaunchReporter.cxx b/Source/CTest/cmCTestLaunchReporter.cxx index 4b4e5c581..149ba5d19 100644 --- a/Source/CTest/cmCTestLaunchReporter.cxx +++ b/Source/CTest/cmCTestLaunchReporter.cxx @@ -2,9 +2,8 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmCTestLaunchReporter.h" -#include - #include "cmsys/FStream.hxx" +#include "cmsys/Process.h" #include "cmsys/RegularExpression.hxx" #include "cmCryptoHash.h" @@ -23,7 +22,6 @@ cmCTestLaunchReporter::cmCTestLaunchReporter() { this->Passthru = true; - this->Status.Finished = true; this->ExitCode = 1; this->CWD = cmSystemTools::GetCurrentWorkingDirectory(); @@ -233,23 +231,35 @@ void cmCTestLaunchReporter::WriteXMLResult(cmXMLElement& e2) // ExitCondition cmXMLElement e4(e3, "ExitCondition"); - if (this->Status.Finished) { - auto exception = this->Status.GetException(); - switch (exception.first) { - case cmUVProcessChain::ExceptionCode::None: - e4.Content(this->ExitCode); - break; - case cmUVProcessChain::ExceptionCode::Spawn: - e4.Content("Error administrating child process: "); - e4.Content(exception.second); - break; - default: - e4.Content("Terminated abnormally: "); - e4.Content(exception.second); - break; - } - } else { - e4.Content("Killed when timeout expired"); + cmsysProcess* cp = this->Process; + switch (cmsysProcess_GetState(cp)) { + case cmsysProcess_State_Starting: + e4.Content("No process has been executed"); + break; + case cmsysProcess_State_Executing: + e4.Content("The process is still executing"); + break; + case cmsysProcess_State_Disowned: + e4.Content("Disowned"); + break; + case cmsysProcess_State_Killed: + e4.Content("Killed by parent"); + break; + + case cmsysProcess_State_Expired: + e4.Content("Killed when timeout expired"); + break; + case cmsysProcess_State_Exited: + e4.Content(this->ExitCode); + break; + case cmsysProcess_State_Exception: + e4.Content("Terminated abnormally: "); + e4.Content(cmsysProcess_GetExceptionString(cp)); + break; + case cmsysProcess_State_Error: + e4.Content("Error administrating child process: "); + e4.Content(cmsysProcess_GetErrorString(cp)); + break; } } diff --git a/Source/CTest/cmCTestLaunchReporter.h b/Source/CTest/cmCTestLaunchReporter.h index 2bb78f8a5..4be0d9beb 100644 --- a/Source/CTest/cmCTestLaunchReporter.h +++ b/Source/CTest/cmCTestLaunchReporter.h @@ -10,8 +10,6 @@ #include "cmsys/RegularExpression.hxx" -#include "cmUVProcessChain.h" - class cmXMLElement; /** \class cmCTestLaunchReporter @@ -50,7 +48,7 @@ public: void ComputeFileNames(); bool Passthru; - cmUVProcessChain::Status Status; + struct cmsysProcess_s* Process; int ExitCode; // Temporary log files for stdout and stderr of real command. diff --git a/Source/CTest/cmCTestP4.cxx b/Source/CTest/cmCTestP4.cxx index 5d71b8460..0e002b9fa 100644 --- a/Source/CTest/cmCTestP4.cxx +++ b/Source/CTest/cmCTestP4.cxx @@ -149,16 +149,17 @@ cmCTestP4::User cmCTestP4::GetUserData(const std::string& username) auto it = this->Users.find(username); if (it == this->Users.end()) { - std::vector p4_users; + std::vector p4_users; this->SetP4Options(p4_users); p4_users.push_back("users"); p4_users.push_back("-m"); p4_users.push_back("1"); - p4_users.push_back(username); + p4_users.push_back(username.c_str()); + p4_users.push_back(nullptr); UserParser out(this, "users-out> "); OutputLogger err(this->Log, "users-err> "); - this->RunChild(p4_users, &out, &err); + this->RunChild(p4_users.data(), &out, &err); // The user should now be added to the map. Search again. it = this->Users.find(username); @@ -302,10 +303,10 @@ private: } }; -void cmCTestP4::SetP4Options(std::vector& CommandOptions) +void cmCTestP4::SetP4Options(std::vector& CommandOptions) { if (this->P4Options.empty()) { - std::string p4 = this->CommandLineTool; + const char* p4 = this->CommandLineTool.c_str(); this->P4Options.emplace_back(p4); // The CTEST_P4_CLIENT variable sets the P4 client used when issuing @@ -327,12 +328,15 @@ void cmCTestP4::SetP4Options(std::vector& CommandOptions) cm::append(this->P4Options, cmSystemTools::ParseArguments(opts)); } - CommandOptions = this->P4Options; + CommandOptions.clear(); + for (std::string const& o : this->P4Options) { + CommandOptions.push_back(o.c_str()); + } } std::string cmCTestP4::GetWorkingRevision() { - std::vector p4_identify; + std::vector p4_identify; this->SetP4Options(p4_identify); p4_identify.push_back("changes"); @@ -341,13 +345,14 @@ std::string cmCTestP4::GetWorkingRevision() p4_identify.push_back("-t"); std::string source = this->SourceDirectory + "/...#have"; - p4_identify.push_back(source); + p4_identify.push_back(source.c_str()); + p4_identify.push_back(nullptr); std::string rev; IdentifyParser out(this, "p4_changes-out> ", rev); OutputLogger err(this->Log, "p4_changes-err> "); - bool result = this->RunChild(p4_identify, &out, &err); + bool result = this->RunChild(p4_identify.data(), &out, &err); // If there was a problem contacting the server return "" if (!result) { @@ -383,7 +388,7 @@ bool cmCTestP4::NoteNewRevision() bool cmCTestP4::LoadRevisions() { - std::vector p4_changes; + std::vector p4_changes; this->SetP4Options(p4_changes); // Use 'p4 changes ...@old,new' to get a list of changelists @@ -404,36 +409,38 @@ bool cmCTestP4::LoadRevisions() .append(this->NewRevision); p4_changes.push_back("changes"); - p4_changes.push_back(range); + p4_changes.push_back(range.c_str()); + p4_changes.push_back(nullptr); ChangesParser out(this, "p4_changes-out> "); OutputLogger err(this->Log, "p4_changes-err> "); this->ChangeLists.clear(); - this->RunChild(p4_changes, &out, &err); + this->RunChild(p4_changes.data(), &out, &err); if (this->ChangeLists.empty()) { return true; } // p4 describe -s ...@1111111,2222222 - std::vector p4_describe; + std::vector p4_describe; for (std::string const& i : cmReverseRange(this->ChangeLists)) { this->SetP4Options(p4_describe); p4_describe.push_back("describe"); p4_describe.push_back("-s"); - p4_describe.push_back(i); + p4_describe.push_back(i.c_str()); + p4_describe.push_back(nullptr); DescribeParser outDescribe(this, "p4_describe-out> "); OutputLogger errDescribe(this->Log, "p4_describe-err> "); - this->RunChild(p4_describe, &outDescribe, &errDescribe); + this->RunChild(p4_describe.data(), &outDescribe, &errDescribe); } return true; } bool cmCTestP4::LoadModifications() { - std::vector p4_diff; + std::vector p4_diff; this->SetP4Options(p4_diff); p4_diff.push_back("diff"); @@ -441,11 +448,12 @@ bool cmCTestP4::LoadModifications() // Ideally we would use -Od but not all clients support it p4_diff.push_back("-dn"); std::string source = this->SourceDirectory + "/..."; - p4_diff.push_back(source); + p4_diff.push_back(source.c_str()); + p4_diff.push_back(nullptr); DiffParser out(this, "p4_diff-out> "); OutputLogger err(this->Log, "p4_diff-err> "); - this->RunChild(p4_diff, &out, &err); + this->RunChild(p4_diff.data(), &out, &err); return true; } @@ -453,14 +461,17 @@ bool cmCTestP4::UpdateCustom(const std::string& custom) { cmList p4_custom_command{ custom, cmList::EmptyElements::Yes }; - std::vector p4_custom; - p4_custom.reserve(p4_custom_command.size()); - cm::append(p4_custom, p4_custom_command); + std::vector p4_custom; + p4_custom.reserve(p4_custom_command.size() + 1); + for (std::string const& i : p4_custom_command) { + p4_custom.push_back(i.c_str()); + } + p4_custom.push_back(nullptr); OutputLogger custom_out(this->Log, "p4_customsync-out> "); OutputLogger custom_err(this->Log, "p4_customsync-err> "); - return this->RunUpdateCommand(p4_custom, &custom_out, &custom_err); + return this->RunUpdateCommand(p4_custom.data(), &custom_out, &custom_err); } bool cmCTestP4::UpdateImpl() @@ -477,7 +488,7 @@ bool cmCTestP4::UpdateImpl() return false; } - std::vector p4_sync; + std::vector p4_sync; this->SetP4Options(p4_sync); p4_sync.push_back("sync"); @@ -488,7 +499,9 @@ bool cmCTestP4::UpdateImpl() opts = this->CTest->GetCTestConfiguration("P4UpdateOptions"); } std::vector args = cmSystemTools::ParseArguments(opts); - cm::append(p4_sync, args); + for (std::string const& arg : args) { + p4_sync.push_back(arg.c_str()); + } std::string source = this->SourceDirectory + "/..."; @@ -502,10 +515,11 @@ bool cmCTestP4::UpdateImpl() source.append("@\"").append(date).append("\""); } - p4_sync.push_back(source); + p4_sync.push_back(source.c_str()); + p4_sync.push_back(nullptr); OutputLogger out(this->Log, "p4_sync-out> "); OutputLogger err(this->Log, "p4_sync-err> "); - return this->RunUpdateCommand(p4_sync, &out, &err); + return this->RunUpdateCommand(p4_sync.data(), &out, &err); } diff --git a/Source/CTest/cmCTestP4.h b/Source/CTest/cmCTestP4.h index 827caa1ad..18895203b 100644 --- a/Source/CTest/cmCTestP4.h +++ b/Source/CTest/cmCTestP4.h @@ -39,7 +39,7 @@ private: std::vector P4Options; User GetUserData(const std::string& username); - void SetP4Options(std::vector& options); + void SetP4Options(std::vector& options); std::string GetWorkingRevision(); bool NoteOldRevision() override; diff --git a/Source/CTest/cmCTestSVN.cxx b/Source/CTest/cmCTestSVN.cxx index 14bc51058..91a1177be 100644 --- a/Source/CTest/cmCTestSVN.cxx +++ b/Source/CTest/cmCTestSVN.cxx @@ -33,7 +33,7 @@ cmCTestSVN::~cmCTestSVN() = default; void cmCTestSVN::CleanupImpl() { - std::vector svn_cleanup; + std::vector svn_cleanup; svn_cleanup.push_back("cleanup"); OutputLogger out(this->Log, "cleanup-out> "); OutputLogger err(this->Log, "cleanup-err> "); @@ -88,9 +88,9 @@ static bool cmCTestSVNPathStarts(std::string const& p1, std::string const& p2) std::string cmCTestSVN::LoadInfo(SVNInfo& svninfo) { // Run "svn info" to get the repository info from the work tree. - std::vector svn_info; + std::vector svn_info; svn_info.push_back("info"); - svn_info.push_back(svninfo.LocalPath); + svn_info.push_back(svninfo.LocalPath.c_str()); std::string rev; InfoParser out(this, "info-out> ", rev, svninfo); OutputLogger err(this->Log, "info-err> "); @@ -251,24 +251,26 @@ bool cmCTestSVN::UpdateImpl() args.push_back("-r{" + this->GetNightlyTime() + " +0000}"); } - std::vector svn_update; + std::vector svn_update; svn_update.push_back("update"); - cm::append(svn_update, args); + for (std::string const& arg : args) { + svn_update.push_back(arg.c_str()); + } UpdateParser out(this, "up-out> "); OutputLogger err(this->Log, "up-err> "); return this->RunSVNCommand(svn_update, &out, &err); } -bool cmCTestSVN::RunSVNCommand(std::vector const& parameters, +bool cmCTestSVN::RunSVNCommand(std::vector const& parameters, OutputParser* out, OutputParser* err) { if (parameters.empty()) { return false; } - std::vector args; - args.push_back(this->CommandLineTool); + std::vector args; + args.push_back(this->CommandLineTool.c_str()); cm::append(args, parameters); args.push_back("--non-interactive"); @@ -276,12 +278,16 @@ bool cmCTestSVN::RunSVNCommand(std::vector const& parameters, std::vector parsedUserOptions = cmSystemTools::ParseArguments(userOptions); - cm::append(args, parsedUserOptions); + for (std::string const& opt : parsedUserOptions) { + args.push_back(opt.c_str()); + } + + args.push_back(nullptr); - if (parameters[0] == "update") { - return this->RunUpdateCommand(args, out, err); + if (strcmp(parameters[0], "update") == 0) { + return this->RunUpdateCommand(args.data(), out, err); } - return this->RunChild(args, out, err); + return this->RunChild(args.data(), out, err); } class cmCTestSVN::LogParser @@ -387,7 +393,7 @@ bool cmCTestSVN::LoadRevisions(SVNInfo& svninfo) } // Run "svn log" to get all global revisions of interest. - std::vector svn_log; + std::vector svn_log; svn_log.push_back("log"); svn_log.push_back("--xml"); svn_log.push_back("-v"); @@ -466,7 +472,7 @@ private: bool cmCTestSVN::LoadModifications() { // Run "svn status" which reports local modifications. - std::vector svn_status; + std::vector svn_status; svn_status.push_back("status"); StatusParser out(this, "status-out> "); OutputLogger err(this->Log, "status-err> "); @@ -528,7 +534,7 @@ bool cmCTestSVN::LoadRepositories() this->RootInfo = &(this->Repositories.back()); // Run "svn status" to get the list of external repositories - std::vector svn_status; + std::vector svn_status; svn_status.push_back("status"); ExternalParser out(this, "external-out> "); OutputLogger err(this->Log, "external-err> "); diff --git a/Source/CTest/cmCTestSVN.h b/Source/CTest/cmCTestSVN.h index 1485dc0fd..370d17682 100644 --- a/Source/CTest/cmCTestSVN.h +++ b/Source/CTest/cmCTestSVN.h @@ -33,7 +33,7 @@ private: bool NoteNewRevision() override; bool UpdateImpl() override; - bool RunSVNCommand(std::vector const& parameters, + bool RunSVNCommand(std::vector const& parameters, OutputParser* out, OutputParser* err); // Information about an SVN repository (root repository or external) diff --git a/Source/CTest/cmCTestScriptHandler.cxx b/Source/CTest/cmCTestScriptHandler.cxx index 48f8f6d18..461ad1a94 100644 --- a/Source/CTest/cmCTestScriptHandler.cxx +++ b/Source/CTest/cmCTestScriptHandler.cxx @@ -11,9 +11,8 @@ #include -#include - #include "cmsys/Directory.hxx" +#include "cmsys/Process.h" #include "cmCTest.h" #include "cmCTestBuildCommand.h" @@ -41,8 +40,6 @@ #include "cmStateSnapshot.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" -#include "cmUVHandlePtr.h" -#include "cmUVProcessChain.h" #include "cmValue.h" #include "cmake.h" @@ -151,65 +148,66 @@ int cmCTestScriptHandler::ExecuteScript(const std::string& total_script_arg) // now pass through all the other arguments std::vector& initArgs = this->CTest->GetInitialCommandLineArguments(); + //*** need to make sure this does not have the current script *** + for (size_t i = 1; i < initArgs.size(); ++i) { + argv.push_back(initArgs[i].c_str()); + } + argv.push_back(nullptr); // Now create process object - cmUVProcessChainBuilder builder; - builder.AddCommand(initArgs) - .SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT) - .SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR); - auto process = builder.Start(); - cm::uv_pipe_ptr outPipe; - outPipe.init(process.GetLoop(), 0); - uv_pipe_open(outPipe, process.OutputStream()); - cm::uv_pipe_ptr errPipe; - errPipe.init(process.GetLoop(), 0); - uv_pipe_open(errPipe, process.ErrorStream()); + cmsysProcess* cp = cmsysProcess_New(); + cmsysProcess_SetCommand(cp, argv.data()); + // cmsysProcess_SetWorkingDirectory(cp, dir); + cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1); + // cmsysProcess_SetTimeout(cp, timeout); + cmsysProcess_Execute(cp); std::vector out; std::vector err; std::string line; - auto pipe = - cmSystemTools::WaitForLine(&process.GetLoop(), outPipe, errPipe, line, - std::chrono::seconds(100), out, err); - while (pipe != cmSystemTools::WaitForLineResult::None) { + int pipe = + cmSystemTools::WaitForLine(cp, line, std::chrono::seconds(100), out, err); + while (pipe != cmsysProcess_Pipe_None) { cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Output: " << line << "\n"); - if (pipe == cmSystemTools::WaitForLineResult::STDERR) { + if (pipe == cmsysProcess_Pipe_STDERR) { cmCTestLog(this->CTest, ERROR_MESSAGE, line << "\n"); - } else if (pipe == cmSystemTools::WaitForLineResult::STDOUT) { + } else if (pipe == cmsysProcess_Pipe_STDOUT) { cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, line << "\n"); } - pipe = - cmSystemTools::WaitForLine(&process.GetLoop(), outPipe, errPipe, line, - std::chrono::seconds(100), out, err); + pipe = cmSystemTools::WaitForLine(cp, line, std::chrono::seconds(100), out, + err); } // Properly handle output of the build command - process.Wait(); - auto const& status = process.GetStatus(0); - auto result = status.GetException(); + cmsysProcess_WaitForExit(cp, nullptr); + int result = cmsysProcess_GetState(cp); int retVal = 0; bool failed = false; - switch (result.first) { - case cmUVProcessChain::ExceptionCode::None: - retVal = static_cast(status.ExitStatus); - break; - case cmUVProcessChain::ExceptionCode::Spawn: - cmCTestLog(this->CTest, ERROR_MESSAGE, - "\tError executing ctest: " << result.second << std::endl); - failed = true; - break; - default: - retVal = status.TermSignal; - cmCTestLog(this->CTest, ERROR_MESSAGE, - "\tThere was an exception: " << result.second << " " << retVal - << std::endl); - failed = true; + if (result == cmsysProcess_State_Exited) { + retVal = cmsysProcess_GetExitValue(cp); + } else if (result == cmsysProcess_State_Exception) { + retVal = cmsysProcess_GetExitException(cp); + cmCTestLog(this->CTest, ERROR_MESSAGE, + "\tThere was an exception: " + << cmsysProcess_GetExceptionString(cp) << " " << retVal + << std::endl); + failed = true; + } else if (result == cmsysProcess_State_Expired) { + cmCTestLog(this->CTest, ERROR_MESSAGE, + "\tThere was a timeout" << std::endl); + failed = true; + } else if (result == cmsysProcess_State_Error) { + cmCTestLog(this->CTest, ERROR_MESSAGE, + "\tError executing ctest: " << cmsysProcess_GetErrorString(cp) + << std::endl); + failed = true; } + cmsysProcess_Delete(cp); if (failed) { std::ostringstream message; message << "Error running command: ["; - message << static_cast(result.first) << "] "; + message << result << "] "; for (const char* arg : argv) { if (arg) { message << arg << " "; diff --git a/Source/CTest/cmCTestVC.cxx b/Source/CTest/cmCTestVC.cxx index cbbb5a5fa..609ccbae9 100644 --- a/Source/CTest/cmCTestVC.cxx +++ b/Source/CTest/cmCTestVC.cxx @@ -7,9 +7,10 @@ #include #include +#include "cmsys/Process.h" + #include "cmCTest.h" #include "cmSystemTools.h" -#include "cmUVProcessChain.h" #include "cmValue.h" #include "cmXMLWriter.h" @@ -54,12 +55,18 @@ bool cmCTestVC::InitialCheckout(const std::string& command) // Construct the initial checkout command line. std::vector args = cmSystemTools::ParseArguments(command); + std::vector vc_co; + vc_co.reserve(args.size() + 1); + for (std::string const& arg : args) { + vc_co.push_back(arg.c_str()); + } + vc_co.push_back(nullptr); // Run the initial checkout command and log its output. this->Log << "--- Begin Initial Checkout ---\n"; OutputLogger out(this->Log, "co-out> "); OutputLogger err(this->Log, "co-err> "); - bool result = this->RunChild(args, &out, &err, parent); + bool result = this->RunChild(vc_co.data(), &out, &err, parent.c_str()); this->Log << "--- End Initial Checkout ---\n"; if (!result) { cmCTestLog(this->CTest, ERROR_MESSAGE, @@ -68,35 +75,35 @@ bool cmCTestVC::InitialCheckout(const std::string& command) return result; } -bool cmCTestVC::RunChild(const std::vector& cmd, - OutputParser* out, OutputParser* err, - std::string workDir, Encoding encoding) +bool cmCTestVC::RunChild(char const* const* cmd, OutputParser* out, + OutputParser* err, const char* workDir, + Encoding encoding) { this->Log << cmCTestVC::ComputeCommandLine(cmd) << "\n"; - cmUVProcessChainBuilder builder; - if (workDir.empty()) { - workDir = this->SourceDirectory; - } - builder.AddCommand(cmd).SetWorkingDirectory(workDir); - auto status = cmCTestVC::RunProcess(builder, out, err, encoding); - return status.front().SpawnResult == 0 && status.front().ExitStatus == 0; + cmsysProcess* cp = cmsysProcess_New(); + cmsysProcess_SetCommand(cp, cmd); + workDir = workDir ? workDir : this->SourceDirectory.c_str(); + cmsysProcess_SetWorkingDirectory(cp, workDir); + cmCTestVC::RunProcess(cp, out, err, encoding); + int result = cmsysProcess_GetExitValue(cp); + cmsysProcess_Delete(cp); + return result == 0; } -std::string cmCTestVC::ComputeCommandLine(const std::vector& cmd) +std::string cmCTestVC::ComputeCommandLine(char const* const* cmd) { std::ostringstream line; const char* sep = ""; - for (auto const& arg : cmd) { - line << sep << "\"" << arg << "\""; + for (const char* const* arg = cmd; *arg; ++arg) { + line << sep << "\"" << *arg << "\""; sep = " "; } return line.str(); } -bool cmCTestVC::RunUpdateCommand(const std::vector& cmd, - OutputParser* out, OutputParser* err, - Encoding encoding) +bool cmCTestVC::RunUpdateCommand(char const* const* cmd, OutputParser* out, + OutputParser* err, Encoding encoding) { // Report the command line. this->UpdateCommandLine = this->ComputeCommandLine(cmd); @@ -106,7 +113,7 @@ bool cmCTestVC::RunUpdateCommand(const std::vector& cmd, } // Run the command. - return this->RunChild(cmd, out, err, "", encoding); + return this->RunChild(cmd, out, err, nullptr, encoding); } std::string cmCTestVC::GetNightlyTime() diff --git a/Source/CTest/cmCTestVC.h b/Source/CTest/cmCTestVC.h index dd5456d87..7b03d1065 100644 --- a/Source/CTest/cmCTestVC.h +++ b/Source/CTest/cmCTestVC.h @@ -6,7 +6,6 @@ #include #include -#include #include "cmProcessOutput.h" #include "cmProcessTools.h" @@ -109,15 +108,15 @@ protected: }; /** Convert a list of arguments to a human-readable command line. */ - static std::string ComputeCommandLine(const std::vector& cmd); + static std::string ComputeCommandLine(char const* const* cmd); /** Run a command line and send output to given parsers. */ - bool RunChild(const std::vector& cmd, OutputParser* out, - OutputParser* err, std::string workDir = {}, + bool RunChild(char const* const* cmd, OutputParser* out, OutputParser* err, + const char* workDir = nullptr, Encoding encoding = cmProcessOutput::Auto); /** Run VC update command line and send output to given parsers. */ - bool RunUpdateCommand(const std::vector& cmd, OutputParser* out, + bool RunUpdateCommand(char const* const* cmd, OutputParser* out, OutputParser* err = nullptr, Encoding encoding = cmProcessOutput::Auto); diff --git a/Source/LexerParser/cmCTestResourceGroupsLexer.cxx b/Source/LexerParser/cmCTestResourceGroupsLexer.cxx index f1d351a57..85b379bbe 100644 --- a/Source/LexerParser/cmCTestResourceGroupsLexer.cxx +++ b/Source/LexerParser/cmCTestResourceGroupsLexer.cxx @@ -667,10 +667,6 @@ Modify cmCTestResourceGroupsLexer.cxx: #include -#ifndef _WIN32 -# include -#endif - /*--------------------------------------------------------------------------*/ #define INITIAL 0 diff --git a/Source/LexerParser/cmCTestResourceGroupsLexer.in.l b/Source/LexerParser/cmCTestResourceGroupsLexer.in.l index ac9cbafe4..2befa85c8 100644 --- a/Source/LexerParser/cmCTestResourceGroupsLexer.in.l +++ b/Source/LexerParser/cmCTestResourceGroupsLexer.in.l @@ -26,10 +26,6 @@ Modify cmCTestResourceGroupsLexer.cxx: #include -#ifndef _WIN32 -# include -#endif - /*--------------------------------------------------------------------------*/ %} diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx index 6e684a354..988a4eb2d 100644 --- a/Source/cmCTest.cxx +++ b/Source/cmCTest.cxx @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include @@ -25,13 +24,13 @@ #include #include -#include #include #include "cmsys/Base64.h" #include "cmsys/Directory.hxx" #include "cmsys/FStream.hxx" #include "cmsys/Glob.hxx" +#include "cmsys/Process.h" #include "cmsys/RegularExpression.hxx" #include "cmsys/SystemInformation.hxx" #if defined(_WIN32) @@ -65,9 +64,6 @@ #include "cmStateTypes.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" -#include "cmUVHandlePtr.h" -#include "cmUVProcessChain.h" -#include "cmUVStream.h" #include "cmValue.h" #include "cmVersion.h" #include "cmVersionConfig.h" @@ -1077,9 +1073,9 @@ int cmCTest::GetTestModelFromString(const std::string& str) // ###################################################################### // ###################################################################### -bool cmCTest::RunMakeCommand(const std::string& command, std::string& output, - int* retVal, const char* dir, cmDuration timeout, - std::ostream& ofs, Encoding encoding) +int cmCTest::RunMakeCommand(const std::string& command, std::string& output, + int* retVal, const char* dir, cmDuration timeout, + std::ostream& ofs, Encoding encoding) { // First generate the command and arguments std::vector args = cmSystemTools::ParseArguments(command); @@ -1088,107 +1084,107 @@ bool cmCTest::RunMakeCommand(const std::string& command, std::string& output, return false; } + std::vector argv; + argv.reserve(args.size() + 1); + for (std::string const& a : args) { + argv.push_back(a.c_str()); + } + argv.push_back(nullptr); + output.clear(); cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, "Run command:"); - for (auto const& arg : args) { + for (char const* arg : argv) { + if (!arg) { + break; + } cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, " \"" << arg << "\""); } cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, std::endl); // Now create process object - cmUVProcessChainBuilder builder; - builder.AddCommand(args).SetMergedBuiltinStreams(); - if (dir) { - builder.SetWorkingDirectory(dir); - } - auto chain = builder.Start(); - cm::uv_pipe_ptr outputStream; - outputStream.init(chain.GetLoop(), 0); - uv_pipe_open(outputStream, chain.OutputStream()); + cmsysProcess* cp = cmsysProcess_New(); + cmsysProcess_SetCommand(cp, argv.data()); + cmsysProcess_SetWorkingDirectory(cp, dir); + cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1); + cmsysProcess_SetTimeout(cp, timeout.count()); + cmsysProcess_Execute(cp); // Initialize tick's std::string::size_type tick = 0; std::string::size_type tick_len = 1024; std::string::size_type tick_line_len = 50; + char* data; + int length; cmProcessOutput processOutput(encoding); + std::string strdata; cmCTestLog(this, HANDLER_PROGRESS_OUTPUT, " Each . represents " << tick_len << " bytes of output\n" " " << std::flush); - auto outputHandle = cmUVStreamRead( - outputStream, - [this, &processOutput, &output, &tick, &tick_len, &tick_line_len, - &ofs](std::vector data) { - std::string strdata; - processOutput.DecodeText(data.data(), data.size(), strdata); - for (char& cc : strdata) { - if (cc == 0) { - cc = '\n'; - } + while (cmsysProcess_WaitForData(cp, &data, &length, nullptr)) { + processOutput.DecodeText(data, length, strdata); + for (char& cc : strdata) { + if (cc == 0) { + cc = '\n'; } - output.append(strdata); - while (output.size() > (tick * tick_len)) { - tick++; - cmCTestLog(this, HANDLER_PROGRESS_OUTPUT, "." << std::flush); - if (tick % tick_line_len == 0 && tick > 0) { - cmCTestLog(this, HANDLER_PROGRESS_OUTPUT, - " Size: " << int((double(output.size()) / 1024.0) + 1) - << "K\n " << std::flush); - } - } - cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, - cmCTestLogWrite(strdata.c_str(), strdata.size())); - if (ofs) { - ofs << cmCTestLogWrite(strdata.c_str(), strdata.size()); - } - }, - [this, &processOutput, &output, &ofs]() { - std::string strdata; - processOutput.DecodeText(std::string(), strdata); - if (!strdata.empty()) { - output.append(strdata); - cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, - cmCTestLogWrite(strdata.c_str(), strdata.size())); - if (ofs) { - ofs << cmCTestLogWrite(strdata.c_str(), strdata.size()); - } + } + output.append(strdata); + while (output.size() > (tick * tick_len)) { + tick++; + cmCTestLog(this, HANDLER_PROGRESS_OUTPUT, "." << std::flush); + if (tick % tick_line_len == 0 && tick > 0) { + cmCTestLog(this, HANDLER_PROGRESS_OUTPUT, + " Size: " << int((double(output.size()) / 1024.0) + 1) + << "K\n " << std::flush); } - }); - - bool finished = chain.Wait(static_cast(timeout.count() * 1000.0)); + } + cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, + cmCTestLogWrite(strdata.c_str(), strdata.size())); + if (ofs) { + ofs << cmCTestLogWrite(strdata.c_str(), strdata.size()); + } + } + processOutput.DecodeText(std::string(), strdata); + if (!strdata.empty()) { + output.append(strdata); + cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, + cmCTestLogWrite(strdata.c_str(), strdata.size())); + if (ofs) { + ofs << cmCTestLogWrite(strdata.c_str(), strdata.size()); + } + } cmCTestLog(this, HANDLER_PROGRESS_OUTPUT, " Size of output: " << int(double(output.size()) / 1024.0) << "K" << std::endl); - if (finished) { - auto const& status = chain.GetStatus(0); - auto exception = status.GetException(); - switch (exception.first) { - case cmUVProcessChain::ExceptionCode::None: - *retVal = static_cast(status.ExitStatus); - cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, - "Command exited with the value: " << *retVal << std::endl); - break; - case cmUVProcessChain::ExceptionCode::Spawn: - output += "\n*** ERROR executing: "; - output += exception.second; - output += "\n***The build process failed."; - cmCTestLog(this, ERROR_MESSAGE, - "There was an error: " << exception.second << std::endl); - break; - default: - *retVal = static_cast(exception.first); - cmCTestLog(this, WARNING, - "There was an exception: " << *retVal << std::endl); - break; - } - } else { + cmsysProcess_WaitForExit(cp, nullptr); + + int result = cmsysProcess_GetState(cp); + + if (result == cmsysProcess_State_Exited) { + *retVal = cmsysProcess_GetExitValue(cp); + cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, + "Command exited with the value: " << *retVal << std::endl); + } else if (result == cmsysProcess_State_Exception) { + *retVal = cmsysProcess_GetExitException(cp); + cmCTestLog(this, WARNING, + "There was an exception: " << *retVal << std::endl); + } else if (result == cmsysProcess_State_Expired) { cmCTestLog(this, WARNING, "There was a timeout" << std::endl); + } else if (result == cmsysProcess_State_Error) { + output += "\n*** ERROR executing: "; + output += cmsysProcess_GetErrorString(cp); + output += "\n***The build process failed."; + cmCTestLog(this, ERROR_MESSAGE, + "There was an error: " << cmsysProcess_GetErrorString(cp) + << std::endl); } - return true; + cmsysProcess_Delete(cp); + + return result; } // ###################################################################### @@ -1196,10 +1192,9 @@ bool cmCTest::RunMakeCommand(const std::string& command, std::string& output, // ###################################################################### // ###################################################################### -bool cmCTest::RunTest(const std::vector& argv, - std::string* output, int* retVal, std::ostream* log, - cmDuration testTimeOut, - std::vector* environment, Encoding encoding) +int cmCTest::RunTest(std::vector argv, std::string* output, + int* retVal, std::ostream* log, cmDuration testTimeOut, + std::vector* environment, Encoding encoding) { bool modifyEnv = (environment && !environment->empty()); @@ -1238,16 +1233,19 @@ bool cmCTest::RunTest(const std::vector& argv, inst.SetStreams(&oss, &oss); std::vector args; - for (auto const& i : argv) { - // make sure we pass the timeout in for any build and test - // invocations. Since --build-generator is required this is a - // good place to check for it, and to add the arguments in - if (i == "--build-generator" && timeout != cmCTest::MaxDuration() && - timeout > cmDuration::zero()) { - args.emplace_back("--test-timeout"); - args.push_back(std::to_string(cmDurationTo(timeout))); + for (char const* i : argv) { + if (i) { + // make sure we pass the timeout in for any build and test + // invocations. Since --build-generator is required this is a + // good place to check for it, and to add the arguments in + if (strcmp(i, "--build-generator") == 0 && + timeout != cmCTest::MaxDuration() && + timeout > cmDuration::zero()) { + args.emplace_back("--test-timeout"); + args.push_back(std::to_string(cmDurationTo(timeout))); + } + args.emplace_back(i); } - args.emplace_back(i); } if (log) { *log << "* Run internal CTest" << std::endl; @@ -1273,7 +1271,7 @@ bool cmCTest::RunTest(const std::vector& argv, << std::endl); } - return true; + return cmsysProcess_State_Exited; } std::vector tempOutput; if (output) { @@ -1286,43 +1284,41 @@ bool cmCTest::RunTest(const std::vector& argv, cmSystemTools::AppendEnv(*environment); } - cmUVProcessChainBuilder builder; - builder.AddCommand(argv).SetMergedBuiltinStreams(); + cmsysProcess* cp = cmsysProcess_New(); + cmsysProcess_SetCommand(cp, argv.data()); cmCTestLog(this, DEBUG, "Command is: " << argv[0] << std::endl); - auto chain = builder.Start(); + if (cmSystemTools::GetRunCommandHideConsole()) { + cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1); + } + cmsysProcess_SetTimeout(cp, timeout.count()); + cmsysProcess_Execute(cp); + + char* data; + int length; cmProcessOutput processOutput(encoding); - cm::uv_pipe_ptr outputStream; - outputStream.init(chain.GetLoop(), 0); - uv_pipe_open(outputStream, chain.OutputStream()); - auto outputHandle = cmUVStreamRead( - outputStream, - [this, &processOutput, &output, &tempOutput, - &log](std::vector data) { - std::string strdata; - processOutput.DecodeText(data.data(), data.size(), strdata); - if (output) { - cm::append(tempOutput, data.data(), data.data() + data.size()); - } - cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, - cmCTestLogWrite(strdata.c_str(), strdata.size())); - if (log) { - log->write(strdata.c_str(), strdata.size()); - } - }, - [this, &processOutput, &log]() { - std::string strdata; - processOutput.DecodeText(std::string(), strdata); - if (!strdata.empty()) { - cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, - cmCTestLogWrite(strdata.c_str(), strdata.size())); - if (log) { - log->write(strdata.c_str(), strdata.size()); - } - } - }); + std::string strdata; + while (cmsysProcess_WaitForData(cp, &data, &length, nullptr)) { + processOutput.DecodeText(data, length, strdata); + if (output) { + cm::append(tempOutput, data, data + length); + } + cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, + cmCTestLogWrite(strdata.c_str(), strdata.size())); + if (log) { + log->write(strdata.c_str(), strdata.size()); + } + } + processOutput.DecodeText(std::string(), strdata); + if (!strdata.empty()) { + cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, + cmCTestLogWrite(strdata.c_str(), strdata.size())); + if (log) { + log->write(strdata.c_str(), strdata.size()); + } + } - bool complete = chain.Wait(static_cast(timeout.count() * 1000.0)); + cmsysProcess_WaitForExit(cp, nullptr); processOutput.DecodeText(tempOutput, tempOutput); if (output && tempOutput.begin() != tempOutput.end()) { output->append(tempOutput.data(), tempOutput.size()); @@ -1330,41 +1326,33 @@ bool cmCTest::RunTest(const std::vector& argv, cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, "-- Process completed" << std::endl); - bool result = false; + int result = cmsysProcess_GetState(cp); - if (complete) { - auto const& status = chain.GetStatus(0); - auto exception = status.GetException(); - switch (exception.first) { - case cmUVProcessChain::ExceptionCode::None: - *retVal = static_cast(status.ExitStatus); - if (*retVal != 0 && this->Impl->OutputTestOutputOnTestFailure) { - this->OutputTestErrors(tempOutput); - } - result = true; - break; - case cmUVProcessChain::ExceptionCode::Spawn: { - std::string outerr = - cmStrCat("\n*** ERROR executing: ", exception.second); - if (output) { - *output += outerr; - } - cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, outerr << std::endl); - } break; - default: { - if (this->Impl->OutputTestOutputOnTestFailure) { - this->OutputTestErrors(tempOutput); - } - *retVal = status.TermSignal; - std::string outerr = - cmStrCat("\n*** Exception executing: ", exception.second); - if (output) { - *output += outerr; - } - cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, outerr << std::endl); - } break; + if (result == cmsysProcess_State_Exited) { + *retVal = cmsysProcess_GetExitValue(cp); + if (*retVal != 0 && this->Impl->OutputTestOutputOnTestFailure) { + this->OutputTestErrors(tempOutput); + } + } else if (result == cmsysProcess_State_Exception) { + if (this->Impl->OutputTestOutputOnTestFailure) { + this->OutputTestErrors(tempOutput); + } + *retVal = cmsysProcess_GetExitException(cp); + std::string outerr = cmStrCat("\n*** Exception executing: ", + cmsysProcess_GetExceptionString(cp)); + if (output) { + *output += outerr; + } + cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, outerr << std::endl); + } else if (result == cmsysProcess_State_Error) { + std::string outerr = + cmStrCat("\n*** ERROR executing: ", cmsysProcess_GetErrorString(cp)); + if (output) { + *output += outerr; } + cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, outerr << std::endl); } + cmsysProcess_Delete(cp); return result; } @@ -3482,70 +3470,49 @@ bool cmCTest::RunCommand(std::vector const& args, stdOut->clear(); stdErr->clear(); - cmUVProcessChainBuilder builder; - builder.AddCommand(args) - .SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT) - .SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR); - if (dir) { - builder.SetWorkingDirectory(dir); - } - auto chain = builder.Start(); - - cm::uv_timer_ptr timer; - bool timedOut = false; - if (timeout.count()) { - timer.init(chain.GetLoop(), &timedOut); - timer.start( - [](uv_timer_t* t) { - auto* timedOutPtr = static_cast(t->data); - *timedOutPtr = true; - }, - static_cast(timeout.count() * 1000.0), 0); + cmsysProcess* cp = cmsysProcess_New(); + cmsysProcess_SetCommand(cp, argv.data()); + cmsysProcess_SetWorkingDirectory(cp, dir); + if (cmSystemTools::GetRunCommandHideConsole()) { + cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1); } + cmsysProcess_SetTimeout(cp, timeout.count()); + cmsysProcess_Execute(cp); std::vector tempOutput; - bool outFinished = false; - cm::uv_pipe_ptr outStream; std::vector tempError; - bool errFinished = false; - cm::uv_pipe_ptr errStream; + char* data; + int length; cmProcessOutput processOutput(encoding); - auto startRead = [this, &chain, &processOutput]( - cm::uv_pipe_ptr& pipe, int stream, - std::vector& temp, - bool& finished) -> std::unique_ptr { - pipe.init(chain.GetLoop(), 0); - uv_pipe_open(pipe, stream); - return cmUVStreamRead( - pipe, - [this, &temp, &processOutput](std::vector data) { - cm::append(temp, data); - if (this->Impl->ExtraVerbose) { - std::string strdata; - processOutput.DecodeText(data.data(), data.size(), strdata); - cmSystemTools::Stdout(strdata); - } - }, - [&finished]() { finished = true; }); - }; - auto outputHandle = - startRead(outStream, chain.OutputStream(), tempOutput, outFinished); - auto errorHandle = - startRead(errStream, chain.ErrorStream(), tempError, errFinished); - while (!timedOut && !(outFinished && errFinished)) { - uv_run(&chain.GetLoop(), UV_RUN_ONCE); + std::string strdata; + int res; + bool done = false; + while (!done) { + res = cmsysProcess_WaitForData(cp, &data, &length, nullptr); + switch (res) { + case cmsysProcess_Pipe_STDOUT: + cm::append(tempOutput, data, data + length); + break; + case cmsysProcess_Pipe_STDERR: + cm::append(tempError, data, data + length); + break; + default: + done = true; + } + if ((res == cmsysProcess_Pipe_STDOUT || res == cmsysProcess_Pipe_STDERR) && + this->Impl->ExtraVerbose) { + processOutput.DecodeText(data, length, strdata); + cmSystemTools::Stdout(strdata); + } } if (this->Impl->ExtraVerbose) { - std::string strdata; processOutput.DecodeText(std::string(), strdata); if (!strdata.empty()) { cmSystemTools::Stdout(strdata); } } - while (!timedOut && !chain.Finished()) { - uv_run(&chain.GetLoop(), UV_RUN_ONCE); - } + cmsysProcess_WaitForExit(cp, nullptr); if (!tempOutput.empty()) { processOutput.DecodeText(tempOutput, tempOutput); stdOut->append(tempOutput.data(), tempOutput.size()); @@ -3556,32 +3523,32 @@ bool cmCTest::RunCommand(std::vector const& args, } bool result = true; - if (timedOut) { + if (cmsysProcess_GetState(cp) == cmsysProcess_State_Exited) { + if (retVal) { + *retVal = cmsysProcess_GetExitValue(cp); + } else { + if (cmsysProcess_GetExitValue(cp) != 0) { + result = false; + } + } + } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Exception) { + const char* exception_str = cmsysProcess_GetExceptionString(cp); + cmCTestLog(this, ERROR_MESSAGE, exception_str << std::endl); + stdErr->append(exception_str, strlen(exception_str)); + result = false; + } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Error) { + const char* error_str = cmsysProcess_GetErrorString(cp); + cmCTestLog(this, ERROR_MESSAGE, error_str << std::endl); + stdErr->append(error_str, strlen(error_str)); + result = false; + } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Expired) { const char* error_str = "Process terminated due to timeout\n"; cmCTestLog(this, ERROR_MESSAGE, error_str << std::endl); stdErr->append(error_str, strlen(error_str)); result = false; - } else { - auto const& status = chain.GetStatus(0); - auto exception = status.GetException(); - switch (exception.first) { - case cmUVProcessChain::ExceptionCode::None: - if (retVal) { - *retVal = static_cast(status.ExitStatus); - } else { - if (status.ExitStatus != 0) { - result = false; - } - } - break; - default: { - cmCTestLog(this, ERROR_MESSAGE, exception.second << std::endl); - stdErr->append(exception.second); - result = false; - } break; - } } + cmsysProcess_Delete(cp); return result; } diff --git a/Source/cmCTest.h b/Source/cmCTest.h index 1644d84b4..9a8d5a65a 100644 --- a/Source/cmCTest.h +++ b/Source/cmCTest.h @@ -254,10 +254,10 @@ public: * Run command specialized for make and configure. Returns process status * and retVal is return value or exception. */ - bool RunMakeCommand(const std::string& command, std::string& output, - int* retVal, const char* dir, cmDuration timeout, - std::ostream& ofs, - Encoding encoding = cmProcessOutput::Auto); + int RunMakeCommand(const std::string& command, std::string& output, + int* retVal, const char* dir, cmDuration timeout, + std::ostream& ofs, + Encoding encoding = cmProcessOutput::Auto); /** Return the current tag */ std::string GetCurrentTag(); @@ -303,10 +303,10 @@ public: * environment variables prior to running the test. After running the test, * environment variables are restored to their previous values. */ - bool RunTest(const std::vector& args, std::string* output, - int* retVal, std::ostream* logfile, cmDuration testTimeOut, - std::vector* environment, - Encoding encoding = cmProcessOutput::Auto); + int RunTest(std::vector args, std::string* output, int* retVal, + std::ostream* logfile, cmDuration testTimeOut, + std::vector* environment, + Encoding encoding = cmProcessOutput::Auto); /** * Get the handler object diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx index 1b69f6e3b..47717e34d 100644 --- a/Source/cmComputeLinkInformation.cxx +++ b/Source/cmComputeLinkInformation.cxx @@ -260,7 +260,7 @@ cmComputeLinkInformation::cmComputeLinkInformation( , Config(config) { // Check whether to recognize OpenBSD-style library versioned names. - this->OpenBSD = this->Makefile->GetState()->GetGlobalPropertyAsBool( + this->IsOpenBSD = this->Makefile->GetState()->GetGlobalPropertyAsBool( "FIND_LIBRARY_USE_OPENBSD_VERSIONING"); // Allocate internals. @@ -553,7 +553,8 @@ bool cmComputeLinkInformation::Compute() this->Target->GetType() == cmStateEnums::MODULE_LIBRARY || this->Target->GetType() == cmStateEnums::STATIC_LIBRARY || (this->Target->CanCompileSources() && - (this->Target->HaveCxx20ModuleSources() || + (this->Target->HaveCxxModuleSupport(this->Config) == + cmGeneratorTarget::Cxx20SupportLevel::Supported || this->Target->HaveFortranSources())))) { return false; } @@ -1574,7 +1575,7 @@ std::string cmComputeLinkInformation::CreateExtensionRegex( libext += ')'; // Add an optional OpenBSD-style version or major.minor.version component. - if (this->OpenBSD || type == LinkShared) { + if (this->IsOpenBSD || type == LinkShared) { libext += "(\\.[0-9]+)*"; } diff --git a/Source/cmComputeLinkInformation.h b/Source/cmComputeLinkInformation.h index 3ee995f08..2a0653003 100644 --- a/Source/cmComputeLinkInformation.h +++ b/Source/cmComputeLinkInformation.h @@ -254,7 +254,7 @@ private: std::unique_ptr OrderRuntimeSearchPath; bool OldLinkDirMode; - bool OpenBSD; + bool IsOpenBSD; bool LinkDependsNoShared; bool RuntimeUseChrpath; bool NoSONameUsesPath; diff --git a/Source/cmDyndepCollation.cxx b/Source/cmDyndepCollation.cxx index 75f88b2e2..edf56ff94 100644 --- a/Source/cmDyndepCollation.cxx +++ b/Source/cmDyndepCollation.cxx @@ -493,7 +493,8 @@ bool cmDyndepCollation::WriteDyndepMetadata( if (!has_provides) { cmSystemTools::Error( cmStrCat("Output ", object.PrimaryOutput, - " is of type `CXX_MODULES` but does not provide a module")); + " is of type `CXX_MODULES` but does not provide a module " + "interface unit or partition")); result = false; continue; } diff --git a/Source/cmExecuteProcessCommand.cxx b/Source/cmExecuteProcessCommand.cxx index e76454584..3efd3bd31 100644 --- a/Source/cmExecuteProcessCommand.cxx +++ b/Source/cmExecuteProcessCommand.cxx @@ -2,8 +2,8 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmExecuteProcessCommand.h" +#include #include /* isspace */ -#include #include #include #include @@ -16,9 +16,7 @@ #include #include -#include - -#include "cm_fileno.hxx" +#include "cmsys/Process.h" #include "cmArgumentParser.h" #include "cmExecutionStatus.h" @@ -28,9 +26,6 @@ #include "cmProcessOutput.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" -#include "cmUVHandlePtr.h" -#include "cmUVProcessChain.h" -#include "cmUVStream.h" namespace { bool cmExecuteProcessCommandIsWhitespace(char c) @@ -41,7 +36,7 @@ bool cmExecuteProcessCommandIsWhitespace(char c) void cmExecuteProcessCommandFixText(std::vector& output, bool strip_trailing_whitespace); void cmExecuteProcessCommandAppend(std::vector& output, const char* data, - std::size_t length); + int length); } // cmExecuteProcessCommand @@ -166,69 +161,57 @@ bool cmExecuteProcessCommand(std::vector const& args, } } // Create a process instance. - cmUVProcessChainBuilder builder; + std::unique_ptr cp_ptr( + cmsysProcess_New(), cmsysProcess_Delete); + cmsysProcess* cp = cp_ptr.get(); // Set the command sequence. for (std::vector const& cmd : arguments.Commands) { - builder.AddCommand(cmd); + std::vector argv(cmd.size() + 1); + std::transform(cmd.begin(), cmd.end(), argv.begin(), + [](std::string const& s) { return s.c_str(); }); + argv.back() = nullptr; + cmsysProcess_AddCommand(cp, argv.data()); } // Set the process working directory. if (!arguments.WorkingDirectory.empty()) { - builder.SetWorkingDirectory(arguments.WorkingDirectory); + cmsysProcess_SetWorkingDirectory(cp, arguments.WorkingDirectory.c_str()); } - // Check the output variables. - std::unique_ptr inputFile(nullptr, fclose); - if (!inputFilename.empty()) { - inputFile.reset(cmsys::SystemTools::Fopen(inputFilename, "rb")); - if (inputFile) { - builder.SetExternalStream(cmUVProcessChainBuilder::Stream_INPUT, - cm_fileno(inputFile.get())); - } - } else { - builder.SetExternalStream(cmUVProcessChainBuilder::Stream_INPUT, - cm_fileno(stdin)); - } + // Always hide the process window. + cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1); - std::unique_ptr outputFile(nullptr, fclose); - if (!outputFilename.empty()) { - outputFile.reset(cmsys::SystemTools::Fopen(outputFilename, "wb")); - if (outputFile) { - builder.SetExternalStream(cmUVProcessChainBuilder::Stream_OUTPUT, - cm_fileno(outputFile.get())); - } - } else { - if (arguments.OutputVariable == arguments.ErrorVariable && - !arguments.ErrorVariable.empty()) { - builder.SetMergedBuiltinStreams(); + // Check the output variables. + bool merge_output = false; + if (!arguments.InputFile.empty()) { + cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDIN, + arguments.InputFile.c_str()); + } + if (!arguments.OutputFile.empty()) { + cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDOUT, + arguments.OutputFile.c_str()); + } + if (!arguments.ErrorFile.empty()) { + if (arguments.ErrorFile == arguments.OutputFile) { + merge_output = true; } else { - builder.SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT); + cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDERR, + arguments.ErrorFile.c_str()); } } - - std::unique_ptr errorFile(nullptr, fclose); - if (!errorFilename.empty()) { - if (errorFilename == outputFilename) { - if (outputFile) { - builder.SetExternalStream(cmUVProcessChainBuilder::Stream_ERROR, - cm_fileno(outputFile.get())); - } - } else { - errorFile.reset(cmsys::SystemTools::Fopen(errorFilename, "wb")); - if (errorFile) { - builder.SetExternalStream(cmUVProcessChainBuilder::Stream_ERROR, - cm_fileno(errorFile.get())); - } - } - } else if (arguments.ErrorVariable.empty() || - (!arguments.ErrorVariable.empty() && - arguments.OutputVariable != arguments.ErrorVariable)) { - builder.SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR); + if (!arguments.OutputVariable.empty() && + arguments.OutputVariable == arguments.ErrorVariable) { + merge_output = true; + } + if (merge_output) { + cmsysProcess_SetOption(cp, cmsysProcess_Option_MergeOutput, 1); } // Set the timeout if any. - int64_t timeoutMillis = static_cast(timeout * 1000.0); + if (timeout >= 0) { + cmsysProcess_SetTimeout(cp, timeout); + } bool echo_stdout = false; bool echo_stderr = false; @@ -276,86 +259,36 @@ bool cmExecuteProcessCommand(std::vector const& args, } } // Start the process. - auto chain = builder.Start(); - - bool timedOut = false; - cm::uv_timer_ptr timer; - - if (timeoutMillis >= 0) { - timer.init(chain.GetLoop(), &timedOut); - timer.start( - [](uv_timer_t* handle) { - auto* timeoutPtr = static_cast(handle->data); - *timeoutPtr = true; - }, - timeoutMillis, 0); - } + cmsysProcess_Execute(cp); // Read the process output. - struct ReadData - { - bool Finished = false; - std::vector Output; - cm::uv_pipe_ptr Stream; - }; - ReadData outputData; - ReadData errorData; + std::vector tempOutput; + std::vector tempError; + int length; + char* data; + int p; cmProcessOutput processOutput( cmProcessOutput::FindEncoding(arguments.Encoding)); std::string strdata; - - std::unique_ptr outputHandle; - if (chain.OutputStream() >= 0) { - outputData.Stream.init(chain.GetLoop(), 0); - uv_pipe_open(outputData.Stream, chain.OutputStream()); - outputHandle = cmUVStreamRead( - outputData.Stream, - [&arguments, &processOutput, &outputData, - &strdata](std::vector data) { - if (!arguments.OutputQuiet) { - if (arguments.OutputVariable.empty() || - arguments.EchoOutputVariable) { - processOutput.DecodeText(data.data(), data.size(), strdata, 1); - cmSystemTools::Stdout(strdata); - } - if (!arguments.OutputVariable.empty()) { - cmExecuteProcessCommandAppend(outputData.Output, data.data(), - data.size()); - } - } - }, - [&outputData]() { outputData.Finished = true; }); - } else { - outputData.Finished = true; - } - std::unique_ptr errorHandle; - if (chain.ErrorStream() >= 0 && - chain.ErrorStream() != chain.OutputStream()) { - errorData.Stream.init(chain.GetLoop(), 0); - uv_pipe_open(errorData.Stream, chain.ErrorStream()); - errorHandle = cmUVStreamRead( - errorData.Stream, - [&arguments, &processOutput, &errorData, - &strdata](std::vector data) { - if (!arguments.ErrorQuiet) { - if (arguments.ErrorVariable.empty() || arguments.EchoErrorVariable) { - processOutput.DecodeText(data.data(), data.size(), strdata, 2); - cmSystemTools::Stderr(strdata); - } - if (!arguments.ErrorVariable.empty()) { - cmExecuteProcessCommandAppend(errorData.Output, data.data(), - data.size()); - } - } - }, - [&errorData]() { errorData.Finished = true; }); - } else { - errorData.Finished = true; - } - - while (chain.Valid() && !timedOut && - !(chain.Finished() && outputData.Finished && errorData.Finished)) { - uv_run(&chain.GetLoop(), UV_RUN_ONCE); + while ((p = cmsysProcess_WaitForData(cp, &data, &length, nullptr))) { + // Put the output in the right place. + if (p == cmsysProcess_Pipe_STDOUT && !arguments.OutputQuiet) { + if (arguments.OutputVariable.empty() || arguments.EchoOutputVariable) { + processOutput.DecodeText(data, length, strdata, 1); + cmSystemTools::Stdout(strdata); + } + if (!arguments.OutputVariable.empty()) { + cmExecuteProcessCommandAppend(tempOutput, data, length); + } + } else if (p == cmsysProcess_Pipe_STDERR && !arguments.ErrorQuiet) { + if (arguments.ErrorVariable.empty() || arguments.EchoErrorVariable) { + processOutput.DecodeText(data, length, strdata, 2); + cmSystemTools::Stderr(strdata); + } + if (!arguments.ErrorVariable.empty()) { + cmExecuteProcessCommandAppend(tempError, data, length); + } + } } if (!arguments.OutputQuiet && (arguments.OutputVariable.empty() || arguments.EchoOutputVariable)) { @@ -372,102 +305,151 @@ bool cmExecuteProcessCommand(std::vector const& args, } } - // All output has been read. - processOutput.DecodeText(outputData.Output, outputData.Output); - processOutput.DecodeText(errorData.Output, errorData.Output); + // All output has been read. Wait for the process to exit. + cmsysProcess_WaitForExit(cp, nullptr); + processOutput.DecodeText(tempOutput, tempOutput); + processOutput.DecodeText(tempError, tempError); // Fix the text in the output strings. - cmExecuteProcessCommandFixText(outputData.Output, + cmExecuteProcessCommandFixText(tempOutput, arguments.OutputStripTrailingWhitespace); - cmExecuteProcessCommandFixText(errorData.Output, + cmExecuteProcessCommandFixText(tempError, arguments.ErrorStripTrailingWhitespace); // Store the output obtained. - if (!arguments.OutputVariable.empty() && !outputData.Output.empty()) { + if (!arguments.OutputVariable.empty() && !tempOutput.empty()) { status.GetMakefile().AddDefinition(arguments.OutputVariable, - outputData.Output.data()); + tempOutput.data()); } - if (arguments.ErrorVariable != arguments.OutputVariable && - !arguments.ErrorVariable.empty() && !errorData.Output.empty()) { + if (!merge_output && !arguments.ErrorVariable.empty() && + !tempError.empty()) { status.GetMakefile().AddDefinition(arguments.ErrorVariable, - errorData.Output.data()); + tempError.data()); } // Store the result of running the process. if (!arguments.ResultVariable.empty()) { - if (timedOut) { - status.GetMakefile().AddDefinition(arguments.ResultVariable, - "Process terminated due to timeout"); - } else { - auto const* lastStatus = chain.GetStatus().back(); - auto exception = lastStatus->GetException(); - if (exception.first == cmUVProcessChain::ExceptionCode::None) { + switch (cmsysProcess_GetState(cp)) { + case cmsysProcess_State_Exited: { + int v = cmsysProcess_GetExitValue(cp); + char buf[16]; + snprintf(buf, sizeof(buf), "%d", v); + status.GetMakefile().AddDefinition(arguments.ResultVariable, buf); + } break; + case cmsysProcess_State_Exception: status.GetMakefile().AddDefinition( - arguments.ResultVariable, - std::to_string(static_cast(lastStatus->ExitStatus))); - } else { + arguments.ResultVariable, cmsysProcess_GetExceptionString(cp)); + break; + case cmsysProcess_State_Error: status.GetMakefile().AddDefinition(arguments.ResultVariable, - exception.second); - } + cmsysProcess_GetErrorString(cp)); + break; + case cmsysProcess_State_Expired: + status.GetMakefile().AddDefinition( + arguments.ResultVariable, "Process terminated due to timeout"); + break; } } // Store the result of running the processes. if (!arguments.ResultsVariable.empty()) { - if (timedOut) { - status.GetMakefile().AddDefinition(arguments.ResultsVariable, - "Process terminated due to timeout"); - } else { - std::vector res; - for (auto const* processStatus : chain.GetStatus()) { - auto exception = processStatus->GetException(); - if (exception.first == cmUVProcessChain::ExceptionCode::None) { - res.emplace_back( - std::to_string(static_cast(processStatus->ExitStatus))); - } else { - res.emplace_back(exception.second); + switch (cmsysProcess_GetState(cp)) { + case cmsysProcess_State_Exited: { + std::vector res; + for (size_t i = 0; i < arguments.Commands.size(); ++i) { + switch (cmsysProcess_GetStateByIndex(cp, static_cast(i))) { + case kwsysProcess_StateByIndex_Exited: { + int exitCode = + cmsysProcess_GetExitValueByIndex(cp, static_cast(i)); + char buf[16]; + snprintf(buf, sizeof(buf), "%d", exitCode); + res.emplace_back(buf); + } break; + case kwsysProcess_StateByIndex_Exception: + res.emplace_back(cmsysProcess_GetExceptionStringByIndex( + cp, static_cast(i))); + break; + case kwsysProcess_StateByIndex_Error: + default: + res.emplace_back("Error getting the child return code"); + break; + } } - } - status.GetMakefile().AddDefinition(arguments.ResultsVariable, - cmList::to_string(res)); + status.GetMakefile().AddDefinition(arguments.ResultsVariable, + cmList::to_string(res)); + } break; + case cmsysProcess_State_Exception: + status.GetMakefile().AddDefinition( + arguments.ResultsVariable, cmsysProcess_GetExceptionString(cp)); + break; + case cmsysProcess_State_Error: + status.GetMakefile().AddDefinition(arguments.ResultsVariable, + cmsysProcess_GetErrorString(cp)); + break; + case cmsysProcess_State_Expired: + status.GetMakefile().AddDefinition( + arguments.ResultsVariable, "Process terminated due to timeout"); + break; } } - auto queryProcessStatusByIndex = [&chain](std::size_t index) -> std::string { - auto const& processStatus = chain.GetStatus(index); - auto exception = processStatus.GetException(); - if (exception.first == cmUVProcessChain::ExceptionCode::None) { - if (processStatus.ExitStatus) { - return cmStrCat("Child return code: ", processStatus.ExitStatus); + auto queryProcessStatusByIndex = [&cp](int index) -> std::string { + std::string processStatus; + switch (cmsysProcess_GetStateByIndex(cp, static_cast(index))) { + case kwsysProcess_StateByIndex_Exited: { + int exitCode = cmsysProcess_GetExitValueByIndex(cp, index); + if (exitCode) { + processStatus = "Child return code: " + std::to_string(exitCode); + } + } break; + case kwsysProcess_StateByIndex_Exception: { + processStatus = cmStrCat( + "Abnormal exit with child return code: ", + cmsysProcess_GetExceptionStringByIndex(cp, static_cast(index))); + break; } - return ""; + case kwsysProcess_StateByIndex_Error: + default: + processStatus = "Error getting the child return code"; + break; } - return cmStrCat("Abnormal exit with child return code: ", - exception.second); + return processStatus; }; if (arguments.CommandErrorIsFatal == "ANY"_s) { bool ret = true; - if (timedOut) { - status.SetError("Process terminated due to timeout"); - ret = false; - } else { - std::map failureIndices; - auto statuses = chain.GetStatus(); - for (std::size_t i = 0; i < statuses.size(); ++i) { - std::string processStatus = queryProcessStatusByIndex(i); - if (!processStatus.empty()) { - failureIndices[i] = processStatus; - } - } - if (!failureIndices.empty()) { - std::ostringstream oss; - oss << "failed command indexes:\n"; - for (auto const& e : failureIndices) { - oss << " " << e.first + 1 << ": \"" << e.second << "\"\n"; + switch (cmsysProcess_GetState(cp)) { + case cmsysProcess_State_Exited: { + std::map failureIndices; + for (int i = 0; i < static_cast(arguments.Commands.size()); ++i) { + std::string processStatus = queryProcessStatusByIndex(i); + if (!processStatus.empty()) { + failureIndices[i] = processStatus; + } + if (!failureIndices.empty()) { + std::ostringstream oss; + oss << "failed command indexes:\n"; + for (auto const& e : failureIndices) { + oss << " " << e.first + 1 << ": \"" << e.second << "\"\n"; + } + status.SetError(oss.str()); + ret = false; + } } - status.SetError(oss.str()); + } break; + case cmsysProcess_State_Exception: + status.SetError( + cmStrCat("abnormal exit: ", cmsysProcess_GetExceptionString(cp))); ret = false; - } + break; + case cmsysProcess_State_Error: + status.SetError(cmStrCat("error getting child return code: ", + cmsysProcess_GetErrorString(cp))); + ret = false; + break; + case cmsysProcess_State_Expired: + status.SetError("Process terminated due to timeout"); + ret = false; + break; } if (!ret) { @@ -478,23 +460,29 @@ bool cmExecuteProcessCommand(std::vector const& args, if (arguments.CommandErrorIsFatal == "LAST"_s) { bool ret = true; - if (timedOut) { - status.SetError("Process terminated due to timeout"); - ret = false; - } else { - auto const& lastStatus = chain.GetStatus(arguments.Commands.size() - 1); - auto exception = lastStatus.GetException(); - if (exception.first != cmUVProcessChain::ExceptionCode::None) { - status.SetError(cmStrCat("Abnormal exit: ", exception.second)); - ret = false; - } else { + switch (cmsysProcess_GetState(cp)) { + case cmsysProcess_State_Exited: { int lastIndex = static_cast(arguments.Commands.size() - 1); const std::string processStatus = queryProcessStatusByIndex(lastIndex); if (!processStatus.empty()) { status.SetError("last command failed"); ret = false; } - } + } break; + case cmsysProcess_State_Exception: + status.SetError( + cmStrCat("Abnormal exit: ", cmsysProcess_GetExceptionString(cp))); + ret = false; + break; + case cmsysProcess_State_Error: + status.SetError(cmStrCat("Error getting child return code: ", + cmsysProcess_GetErrorString(cp))); + ret = false; + break; + case cmsysProcess_State_Expired: + status.SetError("Process terminated due to timeout"); + ret = false; + break; } if (!ret) { cmSystemTools::SetFatalErrorOccurred(); @@ -537,7 +525,7 @@ void cmExecuteProcessCommandFixText(std::vector& output, } void cmExecuteProcessCommandAppend(std::vector& output, const char* data, - std::size_t length) + int length) { #if defined(__APPLE__) // HACK on Apple to work around bug with inserting at the diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx index bf3bb8b88..1a2244539 100644 --- a/Source/cmExportBuildFileGenerator.cxx +++ b/Source/cmExportBuildFileGenerator.cxx @@ -3,6 +3,7 @@ #include "cmExportBuildFileGenerator.h" #include +#include #include #include #include @@ -13,6 +14,7 @@ #include #include +#include "cmCryptoHash.h" #include "cmExportSet.h" #include "cmFileSet.h" #include "cmGeneratedFileStream.h" @@ -156,7 +158,19 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os) this->GenerateTargetFileSets(gte, os); } - this->GenerateCxxModuleInformation(os); + std::string cxx_modules_name; + if (this->ExportSet) { + cxx_modules_name = this->ExportSet->GetName(); + } else { + cmCryptoHash hasher(cmCryptoHash::AlgoSHA3_512); + constexpr std::size_t HASH_TRUNCATION = 12; + for (auto const& target : this->Targets) { + hasher.Append(target); + } + cxx_modules_name = hasher.FinalizeHex().substr(0, HASH_TRUNCATION); + } + + this->GenerateCxxModuleInformation(cxx_modules_name, os); // Generate import file content for each configuration. for (std::string const& c : this->Configurations) { @@ -165,7 +179,7 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os) // Generate import file content for each configuration. for (std::string const& c : this->Configurations) { - this->GenerateImportCxxModuleConfigTargetInclusion(c); + this->GenerateImportCxxModuleConfigTargetInclusion(cxx_modules_name, c); } this->GenerateMissingTargetsCheckCode(os); @@ -506,7 +520,7 @@ std::string cmExportBuildFileGenerator::GetCxxModulesDirectory() const } void cmExportBuildFileGenerator::GenerateCxxModuleConfigInformation( - std::ostream& os) const + std::string const& name, std::ostream& os) const { const char* opt = ""; if (this->Configurations.size() > 1) { @@ -519,13 +533,13 @@ void cmExportBuildFileGenerator::GenerateCxxModuleConfigInformation( if (c.empty()) { c = "noconfig"; } - os << "include(\"${CMAKE_CURRENT_LIST_DIR}/cxx-modules-" << c << ".cmake\"" - << opt << ")\n"; + os << "include(\"${CMAKE_CURRENT_LIST_DIR}/cxx-modules-" << name << '-' + << c << ".cmake\"" << opt << ")\n"; } } bool cmExportBuildFileGenerator::GenerateImportCxxModuleConfigTargetInclusion( - std::string config) const + std::string const& name, std::string config) const { auto cxx_modules_dirname = this->GetCxxModulesDirectory(); if (cxx_modules_dirname.empty()) { @@ -536,8 +550,9 @@ bool cmExportBuildFileGenerator::GenerateImportCxxModuleConfigTargetInclusion( config = "noconfig"; } - std::string fileName = cmStrCat(this->FileDir, '/', cxx_modules_dirname, - "/cxx-modules-", config, ".cmake"); + std::string fileName = + cmStrCat(this->FileDir, '/', cxx_modules_dirname, "/cxx-modules-", name, + '-', config, ".cmake"); cmGeneratedFileStream os(fileName, true); if (!os) { diff --git a/Source/cmExportBuildFileGenerator.h b/Source/cmExportBuildFileGenerator.h index 4636196c8..ea514378c 100644 --- a/Source/cmExportBuildFileGenerator.h +++ b/Source/cmExportBuildFileGenerator.h @@ -92,8 +92,10 @@ protected: cmTargetExport* te) override; std::string GetCxxModulesDirectory() const override; - void GenerateCxxModuleConfigInformation(std::ostream&) const override; - bool GenerateImportCxxModuleConfigTargetInclusion(std::string) const; + void GenerateCxxModuleConfigInformation(std::string const&, + std::ostream&) const override; + bool GenerateImportCxxModuleConfigTargetInclusion(std::string const&, + std::string) const; std::pair, std::string> FindBuildExportInfo( cmGlobalGenerator* gg, const std::string& name); diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index d0e69fbba..f2742df85 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -1461,7 +1461,8 @@ void cmExportFileGenerator::GenerateTargetFileSets(cmGeneratorTarget* gte, } } -void cmExportFileGenerator::GenerateCxxModuleInformation(std::ostream& os) +void cmExportFileGenerator::GenerateCxxModuleInformation( + std::string const& name, std::ostream& os) { auto const cxx_module_dirname = this->GetCxxModulesDirectory(); if (cxx_module_dirname.empty()) { @@ -1471,17 +1472,17 @@ void cmExportFileGenerator::GenerateCxxModuleInformation(std::ostream& os) // Write the include. os << "# Include C++ module properties\n" << "include(\"${CMAKE_CURRENT_LIST_DIR}/" << cxx_module_dirname - << "/cxx-modules.cmake\")\n\n"; + << "/cxx-modules-" << name << ".cmake\")\n\n"; // Get the path to the file we're going to write. std::string path = this->MainImportFile; path = cmSystemTools::GetFilenamePath(path); auto trampoline_path = - cmStrCat(path, '/', cxx_module_dirname, "/cxx-modules.cmake"); + cmStrCat(path, '/', cxx_module_dirname, "/cxx-modules-", name, ".cmake"); // Include all configuration-specific include files. cmGeneratedFileStream ap(trampoline_path, true); ap.SetCopyIfDifferent(true); - this->GenerateCxxModuleConfigInformation(ap); + this->GenerateCxxModuleConfigInformation(name, ap); } diff --git a/Source/cmExportFileGenerator.h b/Source/cmExportFileGenerator.h index f396e0e75..30333d31f 100644 --- a/Source/cmExportFileGenerator.h +++ b/Source/cmExportFileGenerator.h @@ -187,7 +187,7 @@ protected: void GenerateTargetFileSets(cmGeneratorTarget* gte, std::ostream& os, cmTargetExport* te = nullptr); - void GenerateCxxModuleInformation(std::ostream& os); + void GenerateCxxModuleInformation(std::string const& name, std::ostream& os); virtual std::string GetFileSetDirectories(cmGeneratorTarget* gte, cmFileSet* fileSet, @@ -235,5 +235,6 @@ private: const std::string& config) = 0; virtual std::string GetCxxModulesDirectory() const = 0; - virtual void GenerateCxxModuleConfigInformation(std::ostream& os) const = 0; + virtual void GenerateCxxModuleConfigInformation(std::string const&, + std::ostream& os) const = 0; }; diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx index a264f5edd..348b12b16 100644 --- a/Source/cmExportInstallFileGenerator.cxx +++ b/Source/cmExportInstallFileGenerator.cxx @@ -181,10 +181,12 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) bool result = true; - this->GenerateCxxModuleInformation(os); + std::string cxx_modules_name = this->IEGen->GetExportSet()->GetName(); + this->GenerateCxxModuleInformation(cxx_modules_name, os); if (requiresConfigFiles) { for (std::string const& c : this->Configurations) { - if (!this->GenerateImportCxxModuleConfigTargetInclusion(c)) { + if (!this->GenerateImportCxxModuleConfigTargetInclusion(cxx_modules_name, + c)) { result = false; } } @@ -718,12 +720,12 @@ std::string cmExportInstallFileGenerator::GetCxxModulesDirectory() const } void cmExportInstallFileGenerator::GenerateCxxModuleConfigInformation( - std::ostream& os) const + std::string const& name, std::ostream& os) const { // Now load per-configuration properties for them. /* clang-format off */ os << "# Load information for each installed configuration.\n" - "file(GLOB _cmake_cxx_module_includes \"${CMAKE_CURRENT_LIST_DIR}/cxx-modules-*.cmake\")\n" + "file(GLOB _cmake_cxx_module_includes \"${CMAKE_CURRENT_LIST_DIR}/cxx-modules-" << name << "-*.cmake\")\n" "foreach(_cmake_cxx_module_include IN LISTS _cmake_cxx_module_includes)\n" " include(\"${_cmake_cxx_module_include}\")\n" "endforeach()\n" @@ -733,7 +735,8 @@ void cmExportInstallFileGenerator::GenerateCxxModuleConfigInformation( } bool cmExportInstallFileGenerator:: - GenerateImportCxxModuleConfigTargetInclusion(std::string const& config) + GenerateImportCxxModuleConfigTargetInclusion(std::string const& name, + std::string const& config) { auto cxx_modules_dirname = this->GetCxxModulesDirectory(); if (cxx_modules_dirname.empty()) { @@ -748,7 +751,7 @@ bool cmExportInstallFileGenerator:: std::string const dest = cmStrCat(this->FileDir, '/', cxx_modules_dirname, '/'); std::string fileName = - cmStrCat(dest, "cxx-modules-", filename_config, ".cmake"); + cmStrCat(dest, "cxx-modules-", name, '-', filename_config, ".cmake"); cmGeneratedFileStream os(fileName, true); if (!os) { diff --git a/Source/cmExportInstallFileGenerator.h b/Source/cmExportInstallFileGenerator.h index e073a3141..253a65e11 100644 --- a/Source/cmExportInstallFileGenerator.h +++ b/Source/cmExportInstallFileGenerator.h @@ -118,8 +118,10 @@ protected: cmTargetExport* te) override; std::string GetCxxModulesDirectory() const override; - void GenerateCxxModuleConfigInformation(std::ostream&) const override; - bool GenerateImportCxxModuleConfigTargetInclusion(std::string const&); + void GenerateCxxModuleConfigInformation(std::string const&, + std::ostream&) const override; + bool GenerateImportCxxModuleConfigTargetInclusion(std::string const&, + std::string const&); cmInstallExportGenerator* IEGen; diff --git a/Source/cmExportTryCompileFileGenerator.h b/Source/cmExportTryCompileFileGenerator.h index 5c34fad2f..4c7d287c1 100644 --- a/Source/cmExportTryCompileFileGenerator.h +++ b/Source/cmExportTryCompileFileGenerator.h @@ -56,7 +56,10 @@ protected: cmTargetExport* te) override; std::string GetCxxModulesDirectory() const override { return {}; } - void GenerateCxxModuleConfigInformation(std::ostream&) const override {} + void GenerateCxxModuleConfigInformation(std::string const&, + std::ostream&) const override + { + } private: std::string FindTargets(const std::string& prop, diff --git a/Source/cmFindLibraryCommand.cxx b/Source/cmFindLibraryCommand.cxx index df77ad0e6..9df7665ff 100644 --- a/Source/cmFindLibraryCommand.cxx +++ b/Source/cmFindLibraryCommand.cxx @@ -207,7 +207,7 @@ struct cmFindLibraryHelper std::string BestPath; // Support for OpenBSD shared library naming: lib.so.. - bool OpenBSD; + bool IsOpenBSD; bool DebugMode; @@ -320,7 +320,7 @@ cmFindLibraryHelper::cmFindLibraryHelper(std::string debugName, cmMakefile* mf, this->RegexFromList(this->SuffixRegexStr, this->Suffixes); // Check whether to use OpenBSD-style library version comparisons. - this->OpenBSD = this->Makefile->GetState()->GetGlobalPropertyAsBool( + this->IsOpenBSD = this->Makefile->GetState()->GetGlobalPropertyAsBool( "FIND_LIBRARY_USE_OPENBSD_VERSIONING"); } @@ -390,7 +390,7 @@ void cmFindLibraryHelper::AddName(std::string const& name) std::string regex = cmStrCat('^', this->PrefixRegexStr); this->RegexFromLiteral(regex, name); regex += this->SuffixRegexStr; - if (this->OpenBSD) { + if (this->IsOpenBSD) { regex += "(\\.[0-9]+\\.[0-9]+)?"; } regex += "$"; @@ -472,7 +472,7 @@ bool cmFindLibraryHelper::CheckDirectoryForName(std::string const& path, size_type suffix = this->GetSuffixIndex(name.Regex.match(2)); unsigned int major = 0; unsigned int minor = 0; - if (this->OpenBSD) { + if (this->IsOpenBSD) { sscanf(name.Regex.match(3).c_str(), ".%u.%u", &major, &minor); } if (this->BestPath.empty() || prefix < bestPrefix || diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 8af92e545..5b7f52667 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -8319,14 +8319,14 @@ bool cmGeneratorTarget::DiscoverSyntheticTargets(cmSyntheticTargetCache& cache, } if (gt->HaveCxx20ModuleSources()) { - auto hasher = cmCryptoHash::New("SHA3_512"); + cmCryptoHash hasher(cmCryptoHash::AlgoSHA3_512); constexpr size_t HASH_TRUNCATION = 12; - auto dirhash = hasher->HashString( + auto dirhash = hasher.HashString( gt->GetLocalGenerator()->GetCurrentBinaryDirectory()); std::string safeName = gt->GetName(); cmSystemTools::ReplaceString(safeName, ":", "_"); auto targetIdent = - hasher->HashString(cmStrCat("@d_", dirhash, "@u_", usage.GetHash())); + hasher.HashString(cmStrCat("@d_", dirhash, "@u_", usage.GetHash())); std::string targetName = cmStrCat(safeName, "@synth_", targetIdent.substr(0, HASH_TRUNCATION)); @@ -8762,11 +8762,23 @@ bool cmGeneratorTarget::IsFrameworkOnApple() const bool cmGeneratorTarget::IsImportedFrameworkFolderOnApple( const std::string& config) const { - return this->IsApple() && this->IsImported() && - (this->GetType() == cmStateEnums::STATIC_LIBRARY || - this->GetType() == cmStateEnums::SHARED_LIBRARY || - this->GetType() == cmStateEnums::UNKNOWN_LIBRARY) && - cmSystemTools::IsPathToFramework(this->GetLocation(config)); + if (this->IsApple() && this->IsImported() && + (this->GetType() == cmStateEnums::STATIC_LIBRARY || + this->GetType() == cmStateEnums::SHARED_LIBRARY || + this->GetType() == cmStateEnums::UNKNOWN_LIBRARY)) { + std::string cfg = config; + if (cfg.empty() && this->GetGlobalGenerator()->IsXcode()) { + // FIXME(#25515): Remove the need for this workaround. + // The Xcode generator queries include directories without any + // specific configuration. Pick one in case this target does + // not set either IMPORTED_LOCATION or IMPORTED_CONFIGURATIONS. + cfg = + this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig)[0]; + } + return cmSystemTools::IsPathToFramework(this->GetLocation(cfg)); + } + + return false; } bool cmGeneratorTarget::IsAppBundleOnApple() const diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index c2b972d08..5aaa0b8b9 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -1587,6 +1587,13 @@ bool cmGlobalGenerator::Compute() } } + // Add unity sources after computing compile features. Unity sources do + // not change the set of languages or features, but we need to know them + // to filter out sources that are scanned for C++ module dependencies. + if (!this->AddUnitySources()) { + return false; + } + for (const auto& localGen : this->LocalGenerators) { cmMakefile* mf = localGen->GetMakefile(); for (const auto& g : mf->GetInstallGenerators()) { @@ -1863,7 +1870,6 @@ bool cmGlobalGenerator::AddAutomaticSources() if (!gt->CanCompileSources()) { continue; } - lg->AddUnityBuild(gt.get()); lg->AddISPCDependencies(gt.get()); // Targets that reuse a PCH are handled below. if (!gt->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM")) { @@ -1895,6 +1901,28 @@ bool cmGlobalGenerator::AddAutomaticSources() return true; } +bool cmGlobalGenerator::AddUnitySources() +{ + for (const auto& lg : this->LocalGenerators) { + for (const auto& gt : lg->GetGeneratorTargets()) { + if (!gt->CanCompileSources()) { + continue; + } + lg->AddUnityBuild(gt.get()); + } + } + // The above transformation may have changed the classification of sources. + // Clear the source list and classification cache (KindedSources) of all + // targets so that it will be recomputed correctly by the generators later + // now that the above transformations are done for all targets. + for (const auto& lg : this->LocalGenerators) { + for (const auto& gt : lg->GetGeneratorTargets()) { + gt->ClearSourcesCache(); + } + } + return true; +} + std::unique_ptr cmGlobalGenerator::CreateLinkLineComputer( cmOutputConverter* outputConverter, cmStateDirectory const& stateDir) const { diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index aa54f693a..763136e38 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -677,6 +677,7 @@ protected: bool AddHeaderSetVerification(); bool AddAutomaticSources(); + bool AddUnitySources(); std::string SelectMakeProgram(const std::string& makeProgram, const std::string& makeDefault = "") const; diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index cba48f4e3..22fd90dd9 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -564,6 +564,7 @@ cmGlobalNinjaGenerator::cmGlobalNinjaGenerator(cmake* cm) this->Comspec = "cmd.exe"; } #endif + cm->GetState()->SetNinja(true); this->FindMakeProgramFile = "CMakeNinjaFindMake.cmake"; } diff --git a/Source/cmImportedCxxModuleInfo.cxx b/Source/cmImportedCxxModuleInfo.cxx index 9e3ac9ae6..c54b265cb 100644 --- a/Source/cmImportedCxxModuleInfo.cxx +++ b/Source/cmImportedCxxModuleInfo.cxx @@ -4,7 +4,6 @@ #include "cmImportedCxxModuleInfo.h" #include -#include #include #include #include @@ -60,13 +59,13 @@ std::string ImportedCxxModuleLookup::BmiNameForSource(std::string const& path) auto importit = this->ImportedInfo.find(path); std::string bmiName; - auto hasher = cmCryptoHash::New("SHA3_512"); + cmCryptoHash hasher(cmCryptoHash::AlgoSHA3_512); constexpr size_t HASH_TRUNCATION = 12; if (importit != this->ImportedInfo.end()) { - auto safename = hasher->HashString(importit->second.Name); + auto safename = hasher.HashString(importit->second.Name); bmiName = cmStrCat(safename.substr(0, HASH_TRUNCATION), ".bmi"); } else { - auto dirhash = hasher->HashString(path); + auto dirhash = hasher.HashString(path); bmiName = cmStrCat(dirhash.substr(0, HASH_TRUNCATION), ".bmi"); } diff --git a/Source/cmInstallExportGenerator.cxx b/Source/cmInstallExportGenerator.cxx index 71d547192..ead9c0ef3 100644 --- a/Source/cmInstallExportGenerator.cxx +++ b/Source/cmInstallExportGenerator.cxx @@ -158,10 +158,11 @@ void cmInstallExportGenerator::GenerateScriptConfigs(std::ostream& os, // Remove old per-configuration export files if the main changes. std::string installedDir = cmStrCat( "$ENV{DESTDIR}", ConvertToAbsoluteDestination(cxx_module_dest), '/'); - std::string installedFile = cmStrCat(installedDir, "/cxx-modules.cmake"); + std::string installedFile = cmStrCat(installedDir, "/cxx-modules-", + this->ExportSet->GetName(), ".cmake"); std::string toInstallFile = cmStrCat(cmSystemTools::GetFilenamePath(config_file_example), - "/cxx-modules.cmake"); + "/cxx-modules-", this->ExportSet->GetName(), ".cmake"); os << indent << "if(EXISTS \"" << installedFile << "\")\n"; Indent indentN = indent.Next(); Indent indentNN = indentN.Next(); diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 168cd4175..7337ea205 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -3134,6 +3134,15 @@ void cmLocalGenerator::AddUnityBuild(cmGeneratorTarget* target) std::vector sources; target->GetSourceFiles(sources, configs[ci]); for (cmSourceFile* sf : sources) { + // Files which need C++ scanning cannot participate in unity builds as + // there is a single place in TUs that may perform module-dependency bits + // and a unity source cannot `#include` them in-order and represent a + // valid TU. + if (sf->GetLanguage() == "CXX"_s && + target->NeedDyndepForSource("CXX", configs[ci], sf)) { + continue; + } + auto mi = index.find(sf); if (mi == index.end()) { unitySources.emplace_back(sf); diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 74b4b7501..90afb1be4 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -1722,11 +1722,10 @@ void cmMakefileTargetGenerator::GenerateCustomRuleFile( if (!ccg.GetCC().GetDepfile().empty()) { // Add dependency over timestamp file for dependencies management - auto dependTimestamp = cmSystemTools::ConvertToOutputPath( - this->LocalGenerator->MaybeRelativeToTopBinDir( - cmStrCat(this->TargetBuildDirectoryFull, "/compiler_depend.ts"))); + auto dependTimestamp = this->LocalGenerator->MaybeRelativeToTopBinDir( + cmStrCat(this->TargetBuildDirectoryFull, "/compiler_depend.ts")); - depends.push_back(dependTimestamp); + depends.emplace_back(std::move(dependTimestamp)); } // Write the rule. diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 40259186d..1d901940f 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -1373,8 +1373,10 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( bool const needDyndep = !isPch && this->GeneratorTarget->NeedDyndepForSource(language, config, source); - cmNinjaBuild objBuild(this->LanguageCompilerRule( - language, config, needDyndep ? WithScanning::Yes : WithScanning::No)); + WithScanning withScanning = + needDyndep ? WithScanning::Yes : WithScanning::No; + cmNinjaBuild objBuild( + this->LanguageCompilerRule(language, config, withScanning)); cmNinjaVars& vars = objBuild.Variables; vars["FLAGS"] = this->ComputeFlagsForObject(source, language, config, objectFileName); @@ -1434,7 +1436,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( if (firstForConfig) { this->ExportObjectCompileCommand( language, sourceFilePath, objectDir, objectFileName, objectFileDir, - vars["FLAGS"], vars["DEFINES"], vars["INCLUDES"], config); + vars["FLAGS"], vars["DEFINES"], vars["INCLUDES"], config, withScanning); } objBuild.Outputs.push_back(objectFileName); @@ -1780,7 +1782,7 @@ void cmNinjaTargetGenerator::WriteCxxModuleBmiBuildStatement( if (firstForConfig) { this->ExportObjectCompileCommand( language, sourceFilePath, bmiDir, bmiFileName, bmiFileDir, vars["FLAGS"], - vars["DEFINES"], vars["INCLUDES"], config); + vars["DEFINES"], vars["INCLUDES"], config, WithScanning::Yes); } bmiBuild.Outputs.push_back(bmiFileName); @@ -1992,7 +1994,7 @@ void cmNinjaTargetGenerator::ExportObjectCompileCommand( std::string const& objectDir, std::string const& objectFileName, std::string const& objectFileDir, std::string const& flags, std::string const& defines, std::string const& includes, - std::string const& outputConfig) + std::string const& outputConfig, WithScanning withScanning) { if (!this->GeneratorTarget->GetPropertyAsBool("EXPORT_COMPILE_COMMANDS")) { return; @@ -2015,14 +2017,12 @@ void cmNinjaTargetGenerator::ExportObjectCompileCommand( escapedSourceFileName, cmOutputConverter::SHELL); std::string fullFlags = flags; - { - bool const needDyndep = - this->GetGeneratorTarget()->NeedDyndep(language, outputConfig); + if (withScanning == WithScanning::Yes) { std::string const modmapFormatVar = cmStrCat("CMAKE_", language, "_MODULE_MAP_FORMAT"); std::string const modmapFormat = this->Makefile->GetSafeDefinition(modmapFormatVar); - if (needDyndep && !modmapFormat.empty()) { + if (!modmapFormat.empty()) { std::string modmapFlags = this->GetMakefile()->GetRequiredDefinition( cmStrCat("CMAKE_", language, "_MODULE_MAP_FLAG")); // XXX(modmap): If changing this path construction, change diff --git a/Source/cmNinjaTargetGenerator.h b/Source/cmNinjaTargetGenerator.h index 3f5611372..a9bff1d85 100644 --- a/Source/cmNinjaTargetGenerator.h +++ b/Source/cmNinjaTargetGenerator.h @@ -189,7 +189,7 @@ protected: std::string const& objectDir, std::string const& objectFileName, std::string const& objectFileDir, std::string const& flags, std::string const& defines, std::string const& includes, - std::string const& outputConfig); + std::string const& outputConfig, WithScanning withScanning); void AdditionalCleanFiles(const std::string& config); diff --git a/Source/cmOutputConverter.cxx b/Source/cmOutputConverter.cxx index 9c30d74a8..f4a8d0cfa 100644 --- a/Source/cmOutputConverter.cxx +++ b/Source/cmOutputConverter.cxx @@ -275,6 +275,9 @@ std::string cmOutputConverter::EscapeForShell(cm::string_view str, if (this->GetState()->UseNMake()) { flags |= Shell_Flag_NMake; } + if (this->GetState()->UseNinja()) { + flags |= Shell_Flag_Ninja; + } if (!this->GetState()->UseWindowsShell()) { flags |= Shell_Flag_IsUnix; } @@ -677,6 +680,12 @@ std::string cmOutputConverter::Shell_GetArgument(cm::string_view in, int flags) /* Otherwise a semicolon is written just ;. */ out += ';'; } + } else if (*cit == '\n') { + if (flags & Shell_Flag_Ninja) { + out += "$\n"; + } else { + out += '\n'; + } } else { /* Store this character. */ out += *cit; diff --git a/Source/cmOutputConverter.h b/Source/cmOutputConverter.h index 0ee7afb55..424f004d7 100644 --- a/Source/cmOutputConverter.h +++ b/Source/cmOutputConverter.h @@ -100,7 +100,10 @@ public: Shell_Flag_UnescapeNinjaConfiguration = (1 << 9), - Shell_Flag_IsResponse = (1 << 10) + Shell_Flag_IsResponse = (1 << 10), + + /** The target shell is in a Ninja build file. */ + Shell_Flag_Ninja = (1 << 11) }; std::string EscapeForShell(cm::string_view str, bool makeVars = false, diff --git a/Source/cmProcessTools.cxx b/Source/cmProcessTools.cxx index 1dd1dcedd..9e7854b89 100644 --- a/Source/cmProcessTools.cxx +++ b/Source/cmProcessTools.cxx @@ -2,68 +2,48 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmProcessTools.h" -#include -#include #include -#include +#include "cmsys/Process.h" #include "cmProcessOutput.h" -#include "cmUVHandlePtr.h" -#include "cmUVStream.h" -std::vector cmProcessTools::RunProcess( - cmUVProcessChainBuilder& builder, OutputParser* out, OutputParser* err, - Encoding encoding) +void cmProcessTools::RunProcess(struct cmsysProcess_s* cp, OutputParser* out, + OutputParser* err, Encoding encoding) { + cmsysProcess_Execute(cp); + char* data = nullptr; + int length = 0; + int p; cmProcessOutput processOutput(encoding); - - builder.SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT) - .SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR); - - auto chain = builder.Start(); - std::string strdata; - cm::uv_pipe_ptr outputPipe; - outputPipe.init(chain.GetLoop(), 0); - uv_pipe_open(outputPipe, chain.OutputStream()); - auto outputHandle = cmUVStreamRead( - outputPipe, - [&out, &processOutput, &strdata](std::vector data) { - if (out) { - processOutput.DecodeText(data.data(), data.size(), strdata, 1); - if (!out->Process(strdata.c_str(), static_cast(strdata.size()))) { - out = nullptr; - } + while ((out || err) && + (p = cmsysProcess_WaitForData(cp, &data, &length, nullptr))) { + if (out && p == cmsysProcess_Pipe_STDOUT) { + processOutput.DecodeText(data, length, strdata, 1); + if (!out->Process(strdata.c_str(), static_cast(strdata.size()))) { + out = nullptr; } - }, - [&out]() { out = nullptr; }); - cm::uv_pipe_ptr errorPipe; - errorPipe.init(chain.GetLoop(), 0); - uv_pipe_open(errorPipe, chain.ErrorStream()); - auto errorHandle = cmUVStreamRead( - errorPipe, - [&err, &processOutput, &strdata](std::vector data) { - if (err) { - processOutput.DecodeText(data.data(), data.size(), strdata, 2); - if (!err->Process(strdata.c_str(), static_cast(strdata.size()))) { - err = nullptr; - } + } else if (err && p == cmsysProcess_Pipe_STDERR) { + processOutput.DecodeText(data, length, strdata, 2); + if (!err->Process(strdata.c_str(), static_cast(strdata.size()))) { + err = nullptr; } - }, - [&err]() { err = nullptr; }); - while (out || err || !chain.Finished()) { - uv_run(&chain.GetLoop(), UV_RUN_ONCE); + } } - - std::vector result; - auto status = chain.GetStatus(); - std::transform( - status.begin(), status.end(), std::back_inserter(result), - [](const cmUVProcessChain::Status* s) -> cmUVProcessChain::Status { - return *s; - }); - return result; + if (out) { + processOutput.DecodeText(std::string(), strdata, 1); + if (!strdata.empty()) { + out->Process(strdata.c_str(), static_cast(strdata.size())); + } + } + if (err) { + processOutput.DecodeText(std::string(), strdata, 2); + if (!strdata.empty()) { + err->Process(strdata.c_str(), static_cast(strdata.size())); + } + } + cmsysProcess_WaitForExit(cp, nullptr); } cmProcessTools::LineParser::LineParser(char sep, bool ignoreCR) diff --git a/Source/cmProcessTools.h b/Source/cmProcessTools.h index 2bdabea90..74ec5e0b1 100644 --- a/Source/cmProcessTools.h +++ b/Source/cmProcessTools.h @@ -7,10 +7,8 @@ #include #include #include -#include #include "cmProcessOutput.h" -#include "cmUVProcessChain.h" /** \class cmProcessTools * \brief Helper classes for process output parsing @@ -83,7 +81,7 @@ public: }; /** Run a process and send output to given parsers. */ - static std::vector RunProcess( - cmUVProcessChainBuilder& builder, OutputParser* out, - OutputParser* err = nullptr, Encoding encoding = cmProcessOutput::Auto); + static void RunProcess(struct cmsysProcess_s* cp, OutputParser* out, + OutputParser* err = nullptr, + Encoding encoding = cmProcessOutput::Auto); }; diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx index 50b0ebeb2..66544d0f7 100644 --- a/Source/cmQtAutoGenInitializer.cxx +++ b/Source/cmQtAutoGenInitializer.cxx @@ -70,7 +70,7 @@ unsigned int GetParallelCPUCount() return count; } -std::string FileProjectRelativePath(cmMakefile* makefile, +std::string FileProjectRelativePath(cmMakefile const* makefile, std::string const& fileName) { std::string res; @@ -1369,7 +1369,6 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() std::vector dependencies( this->AutogenTarget.DependFiles.begin(), this->AutogenTarget.DependFiles.end()); - if (useDepfile) { // Create a custom command that generates a timestamp file and // has a depfile assigned. The depfile is created by JobDepFilesMergeT. @@ -1408,6 +1407,16 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() cc->SetEscapeOldStyle(false); cmTarget* timestampTarget = this->LocalGen->AddUtilityCommand( timestampTargetName, true, std::move(cc)); + auto const isMake = + this->GlobalGen->GetName().find("Make") != std::string::npos; + if (this->AutogenTarget.DependOrigin && isMake) { + for (BT> const& depName : + this->GenTarget->GetUtilities()) { + timestampTarget->AddUtility(depName.Value.first, false, + this->Makefile); + } + } + this->LocalGen->AddGeneratorTarget( cm::make_unique(timestampTarget, this->LocalGen)); diff --git a/Source/cmState.cxx b/Source/cmState.cxx index 8ae21661b..d104268aa 100644 --- a/Source/cmState.cxx +++ b/Source/cmState.cxx @@ -752,6 +752,16 @@ bool cmState::UseMSYSShell() const return this->MSYSShell; } +void cmState::SetNinja(bool ninja) +{ + this->Ninja = ninja; +} + +bool cmState::UseNinja() const +{ + return this->Ninja; +} + void cmState::SetNinjaMulti(bool ninjaMulti) { this->NinjaMulti = ninjaMulti; diff --git a/Source/cmState.h b/Source/cmState.h index 702b06ff7..ae0d52b67 100644 --- a/Source/cmState.h +++ b/Source/cmState.h @@ -220,6 +220,8 @@ public: bool UseNMake() const; void SetMSYSShell(bool mSYSShell); bool UseMSYSShell() const; + void SetNinja(bool ninja); + bool UseNinja() const; void SetNinjaMulti(bool ninjaMulti); bool UseNinjaMulti() const; @@ -297,6 +299,7 @@ private: bool MinGWMake = false; bool NMake = false; bool MSYSShell = false; + bool Ninja = false; bool NinjaMulti = false; Mode StateMode = Unknown; ProjectKind StateProjectKind = ProjectKind::Normal; diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index f606c229d..2bdc928ed 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -25,17 +25,12 @@ #include -#include "cm_fileno.hxx" - #include "cmDuration.h" #include "cmELF.h" #include "cmMessageMetadata.h" #include "cmProcessOutput.h" #include "cmRange.h" #include "cmStringAlgorithms.h" -#include "cmUVHandlePtr.h" -#include "cmUVProcessChain.h" -#include "cmUVStream.h" #include "cmValue.h" #if !defined(CMAKE_BOOTSTRAP) @@ -64,14 +59,12 @@ #include #include #include -#include #include #include #include #include #include #include -#include #include #include #include @@ -575,115 +568,85 @@ bool cmSystemTools::RunSingleCommand(std::vector const& command, const char* dir, OutputOption outputflag, cmDuration timeout, Encoding encoding) { - cmUVProcessChainBuilder builder; - builder - .SetExternalStream(cmUVProcessChainBuilder::Stream_INPUT, cm_fileno(stdin)) - .AddCommand(command); - if (dir) { - builder.SetWorkingDirectory(dir); + std::vector argv; + argv.reserve(command.size() + 1); + for (std::string const& cmd : command) { + argv.push_back(cmd.c_str()); + } + argv.push_back(nullptr); + + cmsysProcess* cp = cmsysProcess_New(); + cmsysProcess_SetCommand(cp, argv.data()); + cmsysProcess_SetWorkingDirectory(cp, dir); + if (cmSystemTools::GetRunCommandHideConsole()) { + cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1); } if (outputflag == OUTPUT_PASSTHROUGH) { + cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDOUT, 1); + cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDERR, 1); captureStdOut = nullptr; captureStdErr = nullptr; - builder - .SetExternalStream(cmUVProcessChainBuilder::Stream_OUTPUT, - cm_fileno(stdout)) - .SetExternalStream(cmUVProcessChainBuilder::Stream_ERROR, - cm_fileno(stderr)); } else if (outputflag == OUTPUT_MERGE || (captureStdErr && captureStdErr == captureStdOut)) { - builder.SetMergedBuiltinStreams(); + cmsysProcess_SetOption(cp, cmsysProcess_Option_MergeOutput, 1); captureStdErr = nullptr; - } else { - builder.SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT) - .SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR); } assert(!captureStdErr || captureStdErr != captureStdOut); - auto chain = builder.Start(); - bool timedOut = false; - cm::uv_timer_ptr timer; - if (timeout.count()) { - timer.init(chain.GetLoop(), &timedOut); - timer.start( - [](uv_timer_t* t) { - auto* timedOutPtr = static_cast(t->data); - *timedOutPtr = true; - }, - static_cast(timeout.count() * 1000.0), 0); - } + cmsysProcess_SetTimeout(cp, timeout.count()); + cmsysProcess_Execute(cp); std::vector tempStdOut; std::vector tempStdErr; - cm::uv_pipe_ptr outStream; - bool outFinished = true; - cm::uv_pipe_ptr errStream; - bool errFinished = true; + char* data; + int length; + int pipe; cmProcessOutput processOutput(encoding); - std::unique_ptr outputHandle; - std::unique_ptr errorHandle; + std::string strdata; if (outputflag != OUTPUT_PASSTHROUGH && (captureStdOut || captureStdErr || outputflag != OUTPUT_NONE)) { - auto startRead = - [&outputflag, &processOutput, - &chain](cm::uv_pipe_ptr& pipe, int stream, std::string* captureStd, - std::vector& tempStd, int id, - void (*outputFunc)(const std::string&), - bool& finished) -> std::unique_ptr { - if (stream < 0) { - return nullptr; - } - - pipe.init(chain.GetLoop(), 0); - uv_pipe_open(pipe, stream); - - finished = false; - return cmUVStreamRead( - pipe, - [outputflag, &processOutput, captureStd, &tempStd, id, - outputFunc](std::vector data) { - // Translate NULL characters in the output into valid text. - for (auto& c : data) { - if (c == '\0') { - c = ' '; - } - } + while ((pipe = cmsysProcess_WaitForData(cp, &data, &length, nullptr)) > + 0) { + // Translate NULL characters in the output into valid text. + for (int i = 0; i < length; ++i) { + if (data[i] == '\0') { + data[i] = ' '; + } + } - if (outputflag != OUTPUT_NONE) { - std::string strdata; - processOutput.DecodeText(data.data(), data.size(), strdata, id); - outputFunc(strdata); - } - if (captureStd) { - cm::append(tempStd, data.data(), data.data() + data.size()); - } - }, - [&finished, outputflag, &processOutput, id, outputFunc]() { - finished = true; - if (outputflag != OUTPUT_NONE) { - std::string strdata; - processOutput.DecodeText(std::string(), strdata, id); - if (!strdata.empty()) { - outputFunc(strdata); - } - } - }); - }; + if (pipe == cmsysProcess_Pipe_STDOUT) { + if (outputflag != OUTPUT_NONE) { + processOutput.DecodeText(data, length, strdata, 1); + cmSystemTools::Stdout(strdata); + } + if (captureStdOut) { + cm::append(tempStdOut, data, data + length); + } + } else if (pipe == cmsysProcess_Pipe_STDERR) { + if (outputflag != OUTPUT_NONE) { + processOutput.DecodeText(data, length, strdata, 2); + cmSystemTools::Stderr(strdata); + } + if (captureStdErr) { + cm::append(tempStdErr, data, data + length); + } + } + } - outputHandle = - startRead(outStream, chain.OutputStream(), captureStdOut, tempStdOut, 1, - cmSystemTools::Stdout, outFinished); - if (chain.OutputStream() != chain.ErrorStream()) { - errorHandle = - startRead(errStream, chain.ErrorStream(), captureStdErr, tempStdErr, 2, - cmSystemTools::Stderr, errFinished); + if (outputflag != OUTPUT_NONE) { + processOutput.DecodeText(std::string(), strdata, 1); + if (!strdata.empty()) { + cmSystemTools::Stdout(strdata); + } + processOutput.DecodeText(std::string(), strdata, 2); + if (!strdata.empty()) { + cmSystemTools::Stderr(strdata); + } } } - while (!timedOut && !(chain.Finished() && outFinished && errFinished)) { - uv_run(&chain.GetLoop(), UV_RUN_ONCE); - } + cmsysProcess_WaitForExit(cp, nullptr); if (captureStdOut) { captureStdOut->assign(tempStdOut.begin(), tempStdOut.end()); @@ -695,43 +658,48 @@ bool cmSystemTools::RunSingleCommand(std::vector const& command, } bool result = true; - if (timedOut) { - const char* error_str = "Process terminated due to timeout\n"; + if (cmsysProcess_GetState(cp) == cmsysProcess_State_Exited) { + if (retVal) { + *retVal = cmsysProcess_GetExitValue(cp); + } else { + if (cmsysProcess_GetExitValue(cp) != 0) { + result = false; + } + } + } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Exception) { + const char* exception_str = cmsysProcess_GetExceptionString(cp); + if (outputflag != OUTPUT_NONE) { + std::cerr << exception_str << std::endl; + } + if (captureStdErr) { + captureStdErr->append(exception_str, strlen(exception_str)); + } else if (captureStdOut) { + captureStdOut->append(exception_str, strlen(exception_str)); + } + result = false; + } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Error) { + const char* error_str = cmsysProcess_GetErrorString(cp); if (outputflag != OUTPUT_NONE) { std::cerr << error_str << std::endl; } if (captureStdErr) { captureStdErr->append(error_str, strlen(error_str)); + } else if (captureStdOut) { + captureStdOut->append(error_str, strlen(error_str)); } result = false; - } else { - auto const& status = chain.GetStatus(0); - auto exception = status.GetException(); - - switch (exception.first) { - case cmUVProcessChain::ExceptionCode::None: - if (retVal) { - *retVal = static_cast(status.ExitStatus); - } else { - if (status.ExitStatus != 0) { - result = false; - } - } - break; - default: { - if (outputflag != OUTPUT_NONE) { - std::cerr << exception.second << std::endl; - } - if (captureStdErr) { - captureStdErr->append(exception.second); - } else if (captureStdOut) { - captureStdOut->append(exception.second); - } - result = false; - } break; + } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Expired) { + const char* error_str = "Process terminated due to timeout\n"; + if (outputflag != OUTPUT_NONE) { + std::cerr << error_str << std::endl; + } + if (captureStdErr) { + captureStdErr->append(error_str, strlen(error_str)); } + result = false; } + cmsysProcess_Delete(cp); return result; } @@ -2245,10 +2213,9 @@ bool cmSystemTools::ListTar(const std::string& outFileName, #endif } -cmSystemTools::WaitForLineResult cmSystemTools::WaitForLine( - uv_loop_t* loop, uv_stream_t* outPipe, uv_stream_t* errPipe, - std::string& line, cmDuration timeout, std::vector& out, - std::vector& err) +int cmSystemTools::WaitForLine(cmsysProcess* process, std::string& line, + cmDuration timeout, std::vector& out, + std::vector& err) { line.clear(); auto outiter = out.begin(); @@ -2270,7 +2237,7 @@ cmSystemTools::WaitForLineResult cmSystemTools::WaitForLine( line.append(out.data(), length); } out.erase(out.begin(), outiter + 1); - return WaitForLineResult::STDOUT; + return cmsysProcess_Pipe_STDOUT; } } @@ -2288,66 +2255,33 @@ cmSystemTools::WaitForLineResult cmSystemTools::WaitForLine( line.append(err.data(), length); } err.erase(err.begin(), erriter + 1); - return WaitForLineResult::STDERR; + return cmsysProcess_Pipe_STDERR; } } // No newlines found. Wait for more data from the process. - struct ReadData - { - uv_stream_t* Stream; - std::vector Buffer; - bool Read = false; - bool Finished = false; - }; - auto startRead = - [](uv_stream_t* stream, - ReadData& data) -> std::unique_ptr { - data.Stream = stream; - return cmUVStreamRead( - stream, - [&data](std::vector buf) { - data.Buffer = std::move(buf); - data.Read = true; - uv_read_stop(data.Stream); - }, - [&data]() { data.Finished = true; }); - }; - ReadData outData; - auto outHandle = startRead(outPipe, outData); - ReadData errData; - auto errHandle = startRead(errPipe, errData); - - cm::uv_timer_ptr timer; - bool timedOut = false; - timer.init(*loop, &timedOut); - timer.start( - [](uv_timer_t* handle) { - auto* timedOutPtr = static_cast(handle->data); - *timedOutPtr = true; - }, - static_cast(timeout.count() * 1000.0), 0); - - uv_run(loop, UV_RUN_ONCE); - if (timedOut) { + int length; + char* data; + double timeoutAsDbl = timeout.count(); + int pipe = + cmsysProcess_WaitForData(process, &data, &length, &timeoutAsDbl); + if (pipe == cmsysProcess_Pipe_Timeout) { // Timeout has been exceeded. - return WaitForLineResult::Timeout; + return pipe; } - if (outData.Read) { - processOutput.DecodeText(outData.Buffer.data(), outData.Buffer.size(), - strdata, 1); + if (pipe == cmsysProcess_Pipe_STDOUT) { + processOutput.DecodeText(data, length, strdata, 1); // Append to the stdout buffer. std::vector::size_type size = out.size(); cm::append(out, strdata); outiter = out.begin() + size; - } else if (errData.Read) { - processOutput.DecodeText(errData.Buffer.data(), errData.Buffer.size(), - strdata, 2); + } else if (pipe == cmsysProcess_Pipe_STDERR) { + processOutput.DecodeText(data, length, strdata, 2); // Append to the stderr buffer. std::vector::size_type size = err.size(); cm::append(err, strdata); erriter = err.begin() + size; - } else if (outData.Finished && errData.Finished) { + } else if (pipe == cmsysProcess_Pipe_None) { // Both stdout and stderr pipes have broken. Return leftover data. processOutput.DecodeText(std::string(), strdata, 1); if (!strdata.empty()) { @@ -2364,20 +2298,14 @@ cmSystemTools::WaitForLineResult cmSystemTools::WaitForLine( if (!out.empty()) { line.append(out.data(), outiter - out.begin()); out.erase(out.begin(), out.end()); - return WaitForLineResult::STDOUT; + return cmsysProcess_Pipe_STDOUT; } if (!err.empty()) { line.append(err.data(), erriter - err.begin()); err.erase(err.begin(), err.end()); - return WaitForLineResult::STDERR; + return cmsysProcess_Pipe_STDERR; } - return WaitForLineResult::None; - } - if (!outData.Finished) { - uv_read_stop(outPipe); - } - if (!errData.Finished) { - uv_read_stop(errPipe); + return cmsysProcess_Pipe_None; } } } diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h index 7e33e58f1..9563fd639 100644 --- a/Source/cmSystemTools.h +++ b/Source/cmSystemTools.h @@ -18,8 +18,7 @@ #include #include -#include - +#include "cmsys/Process.h" #include "cmsys/Status.hxx" // IWYU pragma: export #include "cmsys/SystemTools.hxx" // IWYU pragma: export @@ -340,20 +339,10 @@ public: */ static void ReportLastSystemError(const char* m); - enum class WaitForLineResult - { - None, - STDOUT, - STDERR, - Timeout, - }; - - /** a general output handler for libuv */ - static WaitForLineResult WaitForLine(uv_loop_t* loop, uv_stream_t* outPipe, - uv_stream_t* errPipe, std::string& line, - cmDuration timeout, - std::vector& out, - std::vector& err); + /** a general output handler for cmsysProcess */ + static int WaitForLine(cmsysProcess* process, std::string& line, + cmDuration timeout, std::vector& out, + std::vector& err); static void SetForceUnixPaths(bool v) { s_ForceUnixPaths = v; } static bool GetForceUnixPaths() { return s_ForceUnixPaths; } diff --git a/Source/cmUVProcessChain.cxx b/Source/cmUVProcessChain.cxx index 655e52aaf..cd452cbcc 100644 --- a/Source/cmUVProcessChain.cxx +++ b/Source/cmUVProcessChain.cxx @@ -12,6 +12,8 @@ #include +#include "cm_fileno.hxx" + #include "cmGetPipes.h" #include "cmUVHandlePtr.h" @@ -57,12 +59,7 @@ struct cmUVProcessChain::InternalData void Finish(); }; -cmUVProcessChainBuilder::cmUVProcessChainBuilder() -{ - this->SetNoStream(Stream_INPUT) - .SetNoStream(Stream_OUTPUT) - .SetNoStream(Stream_ERROR); -} +cmUVProcessChainBuilder::cmUVProcessChainBuilder() = default; cmUVProcessChainBuilder& cmUVProcessChainBuilder::AddCommand( const std::vector& arguments) @@ -122,6 +119,16 @@ cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetExternalStream( return *this; } +cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetExternalStream( + Stream stdio, FILE* stream) +{ + int fd = cm_fileno(stream); + if (fd >= 0) { + return this->SetExternalStream(stdio, fd); + } + return this->SetNoStream(stdio); +} + cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetMergedBuiltinStreams() { this->MergedBuiltinStreams = true; diff --git a/Source/cmUVProcessChain.h b/Source/cmUVProcessChain.h index 0f37e7d0c..aa63ba1d8 100644 --- a/Source/cmUVProcessChain.h +++ b/Source/cmUVProcessChain.h @@ -7,6 +7,7 @@ #include #include // IWYU pragma: keep #include +#include #include #include #include @@ -34,6 +35,7 @@ public: cmUVProcessChainBuilder& SetBuiltinStream(Stream stdio); cmUVProcessChainBuilder& SetMergedBuiltinStreams(); cmUVProcessChainBuilder& SetExternalStream(Stream stdio, int fd); + cmUVProcessChainBuilder& SetExternalStream(Stream stdio, FILE* stream); cmUVProcessChainBuilder& SetWorkingDirectory(std::string dir); cmUVProcessChain Start() const; @@ -50,8 +52,8 @@ private: struct StdioConfiguration { - StdioType Type; - int FileDescriptor; + StdioType Type = None; + int FileDescriptor = -1; }; struct ProcessConfiguration diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 4860d9a60..708cbafaf 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -2784,7 +2784,7 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( isCppModule = true; if (shouldScanForModules && this->GlobalGenerator->IsScanDependenciesSupported()) { - // ScanSourceforModuleDependencies uses 'cl /scanDependencies' and + // ScanSourceForModuleDependencies uses 'cl /scanDependencies' and // can distinguish module interface units and internal partitions. compileAsPerConfig = "CompileAsCpp"; } else { @@ -2827,7 +2827,7 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( // use them if (!flags.empty() || !options.empty() || !configDefines.empty() || !includes.empty() || compileAsPerConfig || noWinRT || - !options.empty() || needsPCHFlags) { + !options.empty() || needsPCHFlags || shouldScanForModules) { cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator; cmIDEFlagTable const* flagtable = nullptr; const std::string& srclang = source->GetLanguage(); @@ -2856,9 +2856,7 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( clOptions.AddFlag("CompileAs", compileAsPerConfig); } if (shouldScanForModules) { - clOptions.AddFlag("ScanSourceforModuleDependencies", "true"); - } else { - clOptions.AddFlag("ScanSourceforModuleDependencies", "false"); + clOptions.AddFlag("ScanSourceForModuleDependencies", "true"); } if (noWinRT) { clOptions.AddFlag("CompileAsWinRT", "false"); @@ -3564,6 +3562,9 @@ void cmVisualStudio10TargetGenerator::WriteClOptions( e2.Element("AdditionalUsingDirectories", dirs); } } + + // Disable C++ source scanning by default. + e2.Element("ScanSourceForModuleDependencies", "false"); } bool cmVisualStudio10TargetGenerator::ComputeRcOptions() diff --git a/Source/cmake.cxx b/Source/cmake.cxx index f54196b04..636a0da5b 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -27,7 +27,6 @@ #include "cmsys/Glob.hxx" #include "cmsys/RegularExpression.hxx" -#include "cm_fileno.hxx" #include "cm_sys_stat.h" #include "cmBuildOptions.h" @@ -3916,10 +3915,8 @@ std::function cmake::BuildWorkflowStep( { cmUVProcessChainBuilder builder; builder.AddCommand(args) - .SetExternalStream(cmUVProcessChainBuilder::Stream_OUTPUT, - cm_fileno(stdout)) - .SetExternalStream(cmUVProcessChainBuilder::Stream_ERROR, - cm_fileno(stderr)); + .SetExternalStream(cmUVProcessChainBuilder::Stream_OUTPUT, stdout) + .SetExternalStream(cmUVProcessChainBuilder::Stream_ERROR, stderr); return [builder]() -> int { auto chain = builder.Start(); chain.Wait(); diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index 43a945f2e..9d7bf50ac 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -11,8 +11,6 @@ #include #include -#include "cm_fileno.hxx" - #include "cmCommandLineArgument.h" #include "cmConsoleBuf.h" #include "cmCryptoHash.h" @@ -74,6 +72,7 @@ #include "cmsys/Directory.hxx" #include "cmsys/FStream.hxx" +#include "cmsys/Process.h" #include "cmsys/RegularExpression.hxx" #include "cmsys/Terminal.h" @@ -296,8 +295,14 @@ int CLCompileAndDependencies(const std::vector& args) } } - cmUVProcessChainBuilder builder; - builder.AddCommand(command).SetWorkingDirectory(currentBinaryDir); + std::unique_ptr cp( + cmsysProcess_New(), cmsysProcess_Delete); + std::vector argv(command.size() + 1); + std::transform(command.begin(), command.end(), argv.begin(), + [](std::string const& s) { return s.c_str(); }); + argv.back() = nullptr; + cmsysProcess_SetCommand(cp.get(), argv.data()); + cmsysProcess_SetWorkingDirectory(cp.get(), currentBinaryDir.c_str()); cmsys::ofstream fout(depFile.c_str()); if (!fout) { @@ -308,18 +313,22 @@ int CLCompileAndDependencies(const std::vector& args) CLOutputLogger errLogger(std::cerr); // Start the process. - auto result = - cmProcessTools::RunProcess(builder, &includeParser, &errLogger); - auto const& subStatus = result.front(); + cmProcessTools::RunProcess(cp.get(), &includeParser, &errLogger); int status = 0; // handle status of process - if (subStatus.SpawnResult != 0) { - status = 2; - } else if (subStatus.TermSignal != 0) { - status = 1; - } else { - status = static_cast(subStatus.ExitStatus); + switch (cmsysProcess_GetState(cp.get())) { + case cmsysProcess_State_Exited: + status = cmsysProcess_GetExitValue(cp.get()); + break; + case cmsysProcess_State_Exception: + status = 1; + break; + case cmsysProcess_State_Error: + status = 2; + break; + default: + break; } if (status != 0) { @@ -1107,8 +1116,7 @@ int cmcmd::ExecuteCMakeCommand(std::vector const& args, int ret = 0; auto time_start = std::chrono::steady_clock::now(); - cmSystemTools::RunSingleCommand(command, nullptr, nullptr, &ret, nullptr, - cmSystemTools::OUTPUT_PASSTHROUGH); + cmSystemTools::RunSingleCommand(command, nullptr, nullptr, &ret); auto time_finish = std::chrono::steady_clock::now(); std::chrono::duration time_elapsed = time_finish - time_start; @@ -1882,6 +1890,21 @@ int cmcmd::ExecuteLinkScript(std::vector const& args) } } + // Allocate a process instance. + cmsysProcess* cp = cmsysProcess_New(); + if (!cp) { + std::cerr << "Error allocating process instance in link script." + << std::endl; + return 1; + } + + // Children should share stdout and stderr with this process. + cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDOUT, 1); + cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDERR, 1); + + // Run the command lines verbatim. + cmsysProcess_SetOption(cp, cmsysProcess_Option_Verbatim, 1); + // Read command lines from the script. cmsys::ifstream fin(args[2].c_str()); if (!fin) { @@ -1899,24 +1922,9 @@ int cmcmd::ExecuteLinkScript(std::vector const& args) continue; } - // Allocate a process instance. - cmUVProcessChainBuilder builder; - - // Children should share stdout and stderr with this process. - builder - .SetExternalStream(cmUVProcessChainBuilder::Stream_OUTPUT, - cm_fileno(stdout)) - .SetExternalStream(cmUVProcessChainBuilder::Stream_ERROR, - cm_fileno(stderr)); - // Setup this command line. - std::vector args2; -#ifdef _WIN32 - cmSystemTools::ParseWindowsCommandLine(command.c_str(), args2); -#else - cmSystemTools::ParseUnixCommandLine(command.c_str(), args2); -#endif - builder.AddCommand(args2); + const char* cmd[2] = { command.c_str(), nullptr }; + cmsysProcess_SetCommand(cp, cmd); // Report the command if verbose output is enabled. if (verbose) { @@ -1924,29 +1932,35 @@ int cmcmd::ExecuteLinkScript(std::vector const& args) } // Run the command and wait for it to exit. - auto chain = builder.Start(); - chain.Wait(); + cmsysProcess_Execute(cp); + cmsysProcess_WaitForExit(cp, nullptr); // Report failure if any. - auto const& status = chain.GetStatus(0); - auto exception = status.GetException(); - switch (exception.first) { - case cmUVProcessChain::ExceptionCode::None: - if (status.ExitStatus != 0) { - result = static_cast(status.ExitStatus); + switch (cmsysProcess_GetState(cp)) { + case cmsysProcess_State_Exited: { + int value = cmsysProcess_GetExitValue(cp); + if (value != 0) { + result = value; } + } break; + case cmsysProcess_State_Exception: + std::cerr << "Error running link command: " + << cmsysProcess_GetExceptionString(cp) << std::endl; + result = 1; break; - case cmUVProcessChain::ExceptionCode::Spawn: - std::cerr << "Error running link command: " << exception.second; + case cmsysProcess_State_Error: + std::cerr << "Error running link command: " + << cmsysProcess_GetErrorString(cp) << std::endl; result = 2; break; default: - std::cerr << "Error running link command: " << exception.second; - result = 1; break; } } + // Free the process instance. + cmsysProcess_Delete(cp); + // Return the final resulting return value. return result; } diff --git a/Tests/CMakeLib/testUVProcessChain.cxx b/Tests/CMakeLib/testUVProcessChain.cxx index aab084b18..c6404ac5a 100644 --- a/Tests/CMakeLib/testUVProcessChain.cxx +++ b/Tests/CMakeLib/testUVProcessChain.cxx @@ -12,8 +12,6 @@ #include -#include "cm_fileno.hxx" - #include "cmGetPipes.h" #include "cmStringAlgorithms.h" #include "cmUVHandlePtr.h" @@ -632,8 +630,7 @@ bool testUVProcessChainInputFile(const char* helperCommand) cmUVProcessChainBuilder builder; builder.AddCommand({ helperCommand, "dedup" }) - .SetExternalStream(cmUVProcessChainBuilder::Stream_INPUT, - cm_fileno(f.get())) + .SetExternalStream(cmUVProcessChainBuilder::Stream_INPUT, f.get()) .SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT); auto chain = builder.Start(); diff --git a/Tests/CMakeLib/testUVProcessChainHelper.cxx b/Tests/CMakeLib/testUVProcessChainHelper.cxx index b53cac480..1b4adb7ec 100644 --- a/Tests/CMakeLib/testUVProcessChainHelper.cxx +++ b/Tests/CMakeLib/testUVProcessChainHelper.cxx @@ -9,6 +9,10 @@ #include "cmSystemTools.h" +#ifdef _WIN32 +# include +#endif + static std::string getStdin() { char buffer[1024]; diff --git a/Tests/CMakeOnly/CMakeLists.txt b/Tests/CMakeOnly/CMakeLists.txt index a41b44ed9..30cabf106 100644 --- a/Tests/CMakeOnly/CMakeLists.txt +++ b/Tests/CMakeOnly/CMakeLists.txt @@ -25,6 +25,13 @@ add_CMakeOnly_test(CheckCXXSymbolExists) add_CMakeOnly_test(CheckCXXCompilerFlag) add_CMakeOnly_test(CheckLanguage) +if (CMake_TEST_HIP) + set_property(TEST CMakeOnly.CheckLanguage APPEND PROPERTY LABELS "HIP") + add_CMakeOnly_test(CheckLanguageHIPPlatform) + set_property(TEST CMakeOnly.CheckLanguageHIPPlatform APPEND PROPERTY LABELS "HIP") + add_CMakeOnly_test(CheckLanguageHIPPlatform2) + set_property(TEST CMakeOnly.CheckLanguageHIPPlatform2 APPEND PROPERTY LABELS "HIP") +endif() add_CMakeOnly_test(CheckStructHasMember) diff --git a/Tests/CMakeOnly/CheckLanguageHIPPlatform/CMakeLists.txt b/Tests/CMakeOnly/CheckLanguageHIPPlatform/CMakeLists.txt new file mode 100644 index 000000000..03b8aa0cf --- /dev/null +++ b/Tests/CMakeOnly/CheckLanguageHIPPlatform/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required (VERSION 3.28) +project(CheckLanguageHIPPlatform NONE) +include(CheckLanguage) + +check_language(HIP) + +if(NOT DEFINED CMAKE_HIP_COMPILER) + message(FATAL_ERROR "check_language did not set result") +endif() + +if (NOT CMAKE_HIP_COMPILER) + message(FATAL_ERROR "check_language should not fail!") +endif() + +if (NOT DEFINED CMAKE_HIP_PLATFORM) + message(FATAL_ERROR "check_language did not set CMAKE_HIP_PLATFORM!") +endif() diff --git a/Tests/CMakeOnly/CheckLanguageHIPPlatform2/CMakeLists.txt b/Tests/CMakeOnly/CheckLanguageHIPPlatform2/CMakeLists.txt new file mode 100644 index 000000000..f251c49b5 --- /dev/null +++ b/Tests/CMakeOnly/CheckLanguageHIPPlatform2/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required (VERSION 3.28) +project(CheckLanguageHIPPlatform2 NONE) +include(CheckLanguage) + +set(CMAKE_HIP_PLATFORM "not-a-hip-platform" CACHE STRING "") +check_language(HIP) + +if(NOT DEFINED CMAKE_HIP_COMPILER) + message(FATAL_ERROR "check_language did not set result") +endif() + +if (CMAKE_HIP_COMPILER) + message(FATAL_ERROR "check_language should have failed") +endif() diff --git a/Tests/Cuda/CMakeLists.txt b/Tests/Cuda/CMakeLists.txt index c737bcc21..efe0358b9 100644 --- a/Tests/Cuda/CMakeLists.txt +++ b/Tests/Cuda/CMakeLists.txt @@ -14,6 +14,7 @@ add_cuda_test_macro(Cuda.MixedStandardLevels5 MixedStandardLevels5) add_cuda_test_macro(Cuda.NotEnabled CudaNotEnabled) add_cuda_test_macro(Cuda.SeparableCompCXXOnly SeparableCompCXXOnly) add_cuda_test_macro(Cuda.StubRPATH StubRPATH) +set(Cuda.Toolkit_BUILD_OPTIONS -DHAS_CUPTI:BOOL=${CMake_TEST_CUDA_CUPTI}) add_cuda_test_macro(Cuda.Toolkit Toolkit) add_cuda_test_macro(Cuda.IncludePathNoToolkit IncludePathNoToolkit) add_cuda_test_macro(Cuda.SharedRuntimePlusToolkit SharedRuntimePlusToolkit) diff --git a/Tests/Cuda/Toolkit/CMakeLists.txt b/Tests/Cuda/Toolkit/CMakeLists.txt index c2989f0ab..4255b82d4 100644 --- a/Tests/Cuda/Toolkit/CMakeLists.txt +++ b/Tests/Cuda/Toolkit/CMakeLists.txt @@ -79,6 +79,23 @@ endforeach() add_executable(Toolkit main.cpp) target_link_libraries(Toolkit PRIVATE CUDA::toolkit) +if(HAS_CUPTI) + set(cupti_libs ) + if(CUDAToolkit_VERSION VERSION_GREATER_EQUAL 10.2) + list(APPEND cupti_libs cupti nvperf_target) + endif() + if(CUDAToolkit_VERSION VERSION_GREATER_EQUAL 11.3) + list(APPEND cupti_libs pcsamplingutil) + endif() + foreach (cuda_lib IN LISTS cupti_libs) + if(NOT CUDA_${cuda_lib}_LIBRARY) + message(FATAL_ERROR "expected CUDAToolkit variable CUDA_${cuda_lib}_LIBRARY not found") + endif() + if(NOT TARGET CUDA::${cuda_lib}) + message(FATAL_ERROR "expected CUDAToolkit target CUDA::${cuda_lib} not found") + endif() + endforeach() +endif() # cupti is an optional component of the CUDA toolkit if(TARGET CUDA::cupti) add_executable(cupti cupti.cpp) diff --git a/Tests/CudaOnly/CMakeLists.txt b/Tests/CudaOnly/CMakeLists.txt index b7ce5a185..82366dfb5 100644 --- a/Tests/CudaOnly/CMakeLists.txt +++ b/Tests/CudaOnly/CMakeLists.txt @@ -12,6 +12,7 @@ add_cuda_test_macro(CudaOnly.ExportPTX CudaOnlyExportPTX) add_cuda_test_macro(CudaOnly.SharedRuntimePlusToolkit CudaOnlySharedRuntimePlusToolkit) add_cuda_test_macro(CudaOnly.StaticRuntimePlusToolkit CudaOnlyStaticRuntimePlusToolkit) add_cuda_test_macro(CudaOnly.Standard98 CudaOnlyStandard98) +set(CudaOnly.Toolkit_BUILD_OPTIONS -DHAS_CUPTI:BOOL=${CMake_TEST_CUDA_CUPTI}) add_cuda_test_macro(CudaOnly.Toolkit CudaOnlyToolkit) add_cuda_test_macro(CudaOnly.ToolkitBeforeLang CudaOnlyToolkitBeforeLang) add_cuda_test_macro(CudaOnly.ToolkitMultipleDirs CudaOnlyToolkitMultipleDirs) diff --git a/Tests/CudaOnly/Toolkit/CMakeLists.txt b/Tests/CudaOnly/Toolkit/CMakeLists.txt index 506fc9fd5..b2694bf66 100644 --- a/Tests/CudaOnly/Toolkit/CMakeLists.txt +++ b/Tests/CudaOnly/Toolkit/CMakeLists.txt @@ -41,7 +41,6 @@ if(CUDAToolkit_VERSION_MAJOR VERSION_LESS 11) list(APPEND cuda_libs nvgraph) endif() - # Verify that all the CUDA:: targets and variables exist foreach (cuda_lib IN LISTS cuda_libs) if(NOT CUDA_${cuda_lib}_LIBRARY) @@ -81,5 +80,24 @@ foreach (cuda_lib nvrtc nvToolsExt OpenCL) endif() endforeach() +if(HAS_CUPTI) + set(cupti_libs ) + if(CUDAToolkit_VERSION VERSION_GREATER_EQUAL 10.2) + list(APPEND cupti_libs cupti nvperf_target) + endif() + if(CUDAToolkit_VERSION VERSION_GREATER_EQUAL 11.3) + list(APPEND cupti_libs pcsamplingutil) + endif() + + foreach (cuda_lib IN LISTS cupti_libs) + if(NOT CUDA_${cuda_lib}_LIBRARY) + message(FATAL_ERROR "expected CUDAToolkit variable CUDA_${cuda_lib}_LIBRARY not found") + endif() + if(NOT TARGET CUDA::${cuda_lib}) + message(FATAL_ERROR "expected CUDAToolkit target CUDA::${cuda_lib} not found") + endif() + endforeach() +endif() + add_executable(CudaOnlyToolkit main.cu) target_link_libraries(CudaOnlyToolkit PRIVATE CUDA::toolkit) diff --git a/Tests/LoadCommand/CMakeCommands/cmTestCommand.c b/Tests/LoadCommand/CMakeCommands/cmTestCommand.c index 7176ebe9d..ba13727d2 100644 --- a/Tests/LoadCommand/CMakeCommands/cmTestCommand.c +++ b/Tests/LoadCommand/CMakeCommands/cmTestCommand.c @@ -16,14 +16,14 @@ static int CCONV InitialPass(void* inf, void* mf, int argc, char* argv[]) { char* file; char* str; - char* srcs; + const char* srcs; const char* cstr; char buffer[1024]; void* source_file; char* args[2]; - char* ccArgs[4]; - char* ccDep[1]; - char* ccOut[1]; + const char* ccArgs[4]; + const char* ccDep[1]; + const char* ccOut[1]; cmLoadedCommandInfo* info = (cmLoadedCommandInfo*)inf; cmVTKWrapTclData* cdata = @@ -148,7 +148,10 @@ static int CCONV InitialPass(void* inf, void* mf, int argc, char* argv[]) if (info->CAPI->GetTotalArgumentSize(2, args) != 13) { return 0; } - info->CAPI->ExecuteCommand(mf, "SET", 2, args); + + ccArgs[0] = "TEST_EXEC"; + ccArgs[1] = "TRUE"; + info->CAPI->ExecuteCommand(mf, "SET", 2, ccArgs); /* make sure we can find the source file */ if (!info->CAPI->GetSource(mf, argv[1])) { diff --git a/Tests/LoadCommandOneConfig/CMakeCommands/cmTestCommand.c b/Tests/LoadCommandOneConfig/CMakeCommands/cmTestCommand.c index 7176ebe9d..e3b332c1a 100644 --- a/Tests/LoadCommandOneConfig/CMakeCommands/cmTestCommand.c +++ b/Tests/LoadCommandOneConfig/CMakeCommands/cmTestCommand.c @@ -16,14 +16,14 @@ static int CCONV InitialPass(void* inf, void* mf, int argc, char* argv[]) { char* file; char* str; - char* srcs; - const char* cstr; + const char* srcs; + char* cstr; char buffer[1024]; void* source_file; char* args[2]; - char* ccArgs[4]; - char* ccDep[1]; - char* ccOut[1]; + const char* ccArgs[4]; + const char* ccDep[1]; + const char* ccOut[1]; cmLoadedCommandInfo* info = (cmLoadedCommandInfo*)inf; cmVTKWrapTclData* cdata = @@ -148,7 +148,10 @@ static int CCONV InitialPass(void* inf, void* mf, int argc, char* argv[]) if (info->CAPI->GetTotalArgumentSize(2, args) != 13) { return 0; } - info->CAPI->ExecuteCommand(mf, "SET", 2, args); + + ccArgs[0] = "TEST_EXEC"; + ccArgs[1] = "TRUE"; + info->CAPI->ExecuteCommand(mf, "SET", 2, ccArgs); /* make sure we can find the source file */ if (!info->CAPI->GetSource(mf, argv[1])) { diff --git a/Tests/QtAutogen/AutogenTimestampDeps/CMakeLists.txt b/Tests/QtAutogen/AutogenTimestampDeps/CMakeLists.txt new file mode 100644 index 000000000..3470a021a --- /dev/null +++ b/Tests/QtAutogen/AutogenTimestampDeps/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.28) +project(AutogenTimestampDeps) +include("../AutogenCoreTest.cmake") + +set(CMAKE_AUTOMOC ON) + +add_custom_target(ProjectInfo + COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/UpdateProjectInfo.cmake + BYPRODUCTS ${CMAKE_BINARY_DIR}/ProjectInfo.hpp) + +add_subdirectory(src) diff --git a/Tests/QtAutogen/AutogenTimestampDeps/ProjectInfo.hpp.in b/Tests/QtAutogen/AutogenTimestampDeps/ProjectInfo.hpp.in new file mode 100644 index 000000000..abaa66cd1 --- /dev/null +++ b/Tests/QtAutogen/AutogenTimestampDeps/ProjectInfo.hpp.in @@ -0,0 +1,6 @@ +#ifndef PROJECTINFO_HPP +#define PROJECTINFO_HPP + +extern int VersionMajor; + +#endif // PROJECTINFO_HPP diff --git a/Tests/QtAutogen/AutogenTimestampDeps/cmake/UpdateProjectInfo.cmake b/Tests/QtAutogen/AutogenTimestampDeps/cmake/UpdateProjectInfo.cmake new file mode 100644 index 000000000..8dd8d5548 --- /dev/null +++ b/Tests/QtAutogen/AutogenTimestampDeps/cmake/UpdateProjectInfo.cmake @@ -0,0 +1,2 @@ + +configure_file(${CMAKE_CURRENT_LIST_DIR}/../ProjectInfo.hpp.in ${CMAKE_BINARY_DIR}/ProjectInfo.hpp @ONLY) diff --git a/Tests/QtAutogen/AutogenTimestampDeps/src/CMakeLists.txt b/Tests/QtAutogen/AutogenTimestampDeps/src/CMakeLists.txt new file mode 100644 index 000000000..e931248e5 --- /dev/null +++ b/Tests/QtAutogen/AutogenTimestampDeps/src/CMakeLists.txt @@ -0,0 +1,4 @@ +add_executable(Exe main.cpp ${CMAKE_BINARY_DIR}/ProjectInfo.hpp) +add_dependencies(Exe ProjectInfo) +target_include_directories(Exe PRIVATE ${CMAKE_BINARY_DIR}) +target_link_libraries(Exe PRIVATE ${QT_QTCORE_TARGET}) diff --git a/Tests/QtAutogen/AutogenTimestampDeps/src/main.cpp b/Tests/QtAutogen/AutogenTimestampDeps/src/main.cpp new file mode 100644 index 000000000..f3c4c4b0c --- /dev/null +++ b/Tests/QtAutogen/AutogenTimestampDeps/src/main.cpp @@ -0,0 +1,5 @@ +#include "ProjectInfo.hpp" +int main(int argc, char* argv[]) +{ + return 0; +} diff --git a/Tests/QtAutogen/Tests.cmake b/Tests/QtAutogen/Tests.cmake index d676abde3..80f732973 100644 --- a/Tests/QtAutogen/Tests.cmake +++ b/Tests/QtAutogen/Tests.cmake @@ -2,6 +2,7 @@ ADD_AUTOGEN_TEST(AutogenOriginDependsOff autogenOriginDependsOff) ADD_AUTOGEN_TEST(AutogenOriginDependsOn) ADD_AUTOGEN_TEST(AutogenTargetDepends) +ADD_AUTOGEN_TEST(AutogenTimestampDeps) ADD_AUTOGEN_TEST(AutoMocGeneratedFile) ADD_AUTOGEN_TEST(Complex QtAutogen) ADD_AUTOGEN_TEST(GlobalAutogenSystemUseInclude) diff --git a/Tests/RunCMake/BuildDepends/CustomCommandDepfile.cmake b/Tests/RunCMake/BuildDepends/CustomCommandDepfile.cmake index 19c09c837..c3725a4d1 100644 --- a/Tests/RunCMake/BuildDepends/CustomCommandDepfile.cmake +++ b/Tests/RunCMake/BuildDepends/CustomCommandDepfile.cmake @@ -24,6 +24,17 @@ add_library(toplib STATIC toplib.c) add_subdirectory(DepfileSubdir) +set(TEST_SPACE 1) +if(CMAKE_GENERATOR STREQUAL "Unix Makefiles") + execute_process(COMMAND "${CMAKE_MAKE_PROGRAM}" no_such_target --version RESULT_VARIABLE res OUTPUT_VARIABLE out ERROR_VARIABLE out) + if(NOT res EQUAL 0 OR NOT out MATCHES "GNU") + set(TEST_SPACE 0) + endif() +endif() +if(TEST_SPACE) + add_subdirectory(DepfileSubdirWithSpace) +endif() + add_custom_command( OUTPUT toplib2.c DEPFILE toplib2.c.d diff --git a/Tests/RunCMake/BuildDepends/DepfileSubdirWithSpace/CMakeLists.txt b/Tests/RunCMake/BuildDepends/DepfileSubdirWithSpace/CMakeLists.txt new file mode 100644 index 000000000..204f7408a --- /dev/null +++ b/Tests/RunCMake/BuildDepends/DepfileSubdirWithSpace/CMakeLists.txt @@ -0,0 +1,2 @@ + +add_subdirectory("path with space") diff --git a/Tests/RunCMake/BuildDepends/DepfileSubdirWithSpace/path with space/CMakeLists.txt b/Tests/RunCMake/BuildDepends/DepfileSubdirWithSpace/path with space/CMakeLists.txt new file mode 100644 index 000000000..37c0a5701 --- /dev/null +++ b/Tests/RunCMake/BuildDepends/DepfileSubdirWithSpace/path with space/CMakeLists.txt @@ -0,0 +1,9 @@ + +add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/dummy.txt" + COMMAND ${CMAKE_COMMAND} -E touch "${CMAKE_CURRENT_BINARY_DIR}/dummy.txt" + DEPFILE dummy.txt.d +) + +add_custom_target(subdir_space ALL + DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/dummy.txt" +) diff --git a/Tests/RunCMake/CXXModules/ExportBuildCxxModules-check.cmake b/Tests/RunCMake/CXXModules/ExportBuildCxxModules-check.cmake index cb6f6bdc3..94d447976 100644 --- a/Tests/RunCMake/CXXModules/ExportBuildCxxModules-check.cmake +++ b/Tests/RunCMake/CXXModules/ExportBuildCxxModules-check.cmake @@ -1,19 +1,19 @@ file(READ "${RunCMake_TEST_BINARY_DIR}/lib/cmake/export-modules/export-modules-targets.cmake" export_script) -if (NOT export_script MATCHES [[include\("\${CMAKE_CURRENT_LIST_DIR}/cxx-modules/cxx-modules\.cmake"\)]]) +if (NOT export_script MATCHES [[include\("\${CMAKE_CURRENT_LIST_DIR}/cxx-modules/cxx-modules-exp\.cmake"\)]]) list(APPEND RunCMake_TEST_FAILED "Could not find C++ module property script inclusion") endif () -file(READ "${RunCMake_TEST_BINARY_DIR}/lib/cmake/export-modules/cxx-modules/cxx-modules.cmake" trampoline_script) +file(READ "${RunCMake_TEST_BINARY_DIR}/lib/cmake/export-modules/cxx-modules/cxx-modules-exp.cmake" trampoline_script) if (RunCMake_GENERATOR_IS_MULTI_CONFIG) - if (NOT trampoline_script MATCHES [[include\("\${CMAKE_CURRENT_LIST_DIR}/cxx-modules-[^.]*\.cmake" OPTIONAL\)]]) + if (NOT trampoline_script MATCHES [[include\("\${CMAKE_CURRENT_LIST_DIR}/cxx-modules-exp-[^.]*\.cmake" OPTIONAL\)]]) list(APPEND RunCMake_TEST_FAILED "Could not find C++ module property per-config script inclusion(s)") endif () else () - if (NOT trampoline_script MATCHES [[include\("\${CMAKE_CURRENT_LIST_DIR}/cxx-modules-[^.]*\.cmake"\)]]) + if (NOT trampoline_script MATCHES [[include\("\${CMAKE_CURRENT_LIST_DIR}/cxx-modules-exp-[^.]*\.cmake"\)]]) list(APPEND RunCMake_TEST_FAILED "Could not find C++ module property per-config script inclusion(s)") endif () @@ -21,12 +21,12 @@ endif () set(any_exists 0) foreach (config IN ITEMS noconfig Debug Release RelWithDebInfo MinSizeRel) - if (NOT EXISTS "${RunCMake_TEST_BINARY_DIR}/lib/cmake/export-modules/cxx-modules/cxx-modules-${config}.cmake") + if (NOT EXISTS "${RunCMake_TEST_BINARY_DIR}/lib/cmake/export-modules/cxx-modules/cxx-modules-exp-${config}.cmake") continue () endif () set(any_exists 1) - file(READ "${RunCMake_TEST_BINARY_DIR}/lib/cmake/export-modules/cxx-modules/cxx-modules-${config}.cmake" config_script) + file(READ "${RunCMake_TEST_BINARY_DIR}/lib/cmake/export-modules/cxx-modules/cxx-modules-exp-${config}.cmake" config_script) if (NOT config_script MATCHES "include\\(\"\\\${CMAKE_CURRENT_LIST_DIR}/target-export-name-${config}\\.cmake\"\\)") list(APPEND RunCMake_TEST_FAILED diff --git a/Tests/RunCMake/CXXModules/ExportBuildCxxModulesTargets-check.cmake b/Tests/RunCMake/CXXModules/ExportBuildCxxModulesTargets-check.cmake new file mode 100644 index 000000000..0402fd7cd --- /dev/null +++ b/Tests/RunCMake/CXXModules/ExportBuildCxxModulesTargets-check.cmake @@ -0,0 +1,40 @@ +file(READ "${RunCMake_TEST_BINARY_DIR}/lib/cmake/export-modules/export-modules-targets.cmake" export_script) + +if (NOT export_script MATCHES [[include\("\${CMAKE_CURRENT_LIST_DIR}/cxx-modules/cxx-modules-7eb8e1b4d8a1\.cmake"\)]]) + list(APPEND RunCMake_TEST_FAILED + "Could not find C++ module property script inclusion") +endif () + +file(READ "${RunCMake_TEST_BINARY_DIR}/lib/cmake/export-modules/cxx-modules/cxx-modules-7eb8e1b4d8a1.cmake" trampoline_script) + +if (RunCMake_GENERATOR_IS_MULTI_CONFIG) + if (NOT trampoline_script MATCHES [[include\("\${CMAKE_CURRENT_LIST_DIR}/cxx-modules-7eb8e1b4d8a1-[^.]*\.cmake" OPTIONAL\)]]) + list(APPEND RunCMake_TEST_FAILED + "Could not find C++ module property per-config script inclusion(s)") + endif () +else () + if (NOT trampoline_script MATCHES [[include\("\${CMAKE_CURRENT_LIST_DIR}/cxx-modules-7eb8e1b4d8a1-[^.]*\.cmake"\)]]) + list(APPEND RunCMake_TEST_FAILED + "Could not find C++ module property per-config script inclusion(s)") + endif () +endif () + +set(any_exists 0) +foreach (config IN ITEMS noconfig Debug Release RelWithDebInfo MinSizeRel) + if (NOT EXISTS "${RunCMake_TEST_BINARY_DIR}/lib/cmake/export-modules/cxx-modules/cxx-modules-7eb8e1b4d8a1-${config}.cmake") + continue () + endif () + set(any_exists 1) + + file(READ "${RunCMake_TEST_BINARY_DIR}/lib/cmake/export-modules/cxx-modules/cxx-modules-7eb8e1b4d8a1-${config}.cmake" config_script) + + if (NOT config_script MATCHES "include\\(\"\\\${CMAKE_CURRENT_LIST_DIR}/target-export-name-${config}\\.cmake\"\\)") + list(APPEND RunCMake_TEST_FAILED + "Could not find C++ module per-target property script inclusion") + endif () +endforeach () + +if (NOT any_exists) + list(APPEND RunCMake_TEST_FAILED + "No per-configuration target files exist.") +endif () diff --git a/Tests/RunCMake/CXXModules/ExportBuildCxxModulesTargets.cmake b/Tests/RunCMake/CXXModules/ExportBuildCxxModulesTargets.cmake new file mode 100644 index 000000000..1da649858 --- /dev/null +++ b/Tests/RunCMake/CXXModules/ExportBuildCxxModulesTargets.cmake @@ -0,0 +1,21 @@ +enable_language(CXX) +set(CMAKE_CXX_SCANDEP_SOURCE "") + +add_library(export-modules) +target_sources(export-modules + PUBLIC + FILE_SET fs TYPE CXX_MODULES FILES + sources/module.cxx) +target_compile_features(export-modules + PRIVATE + cxx_std_20) +set_property(TARGET export-modules + PROPERTY EXPORT_NAME export-name) + +install(TARGETS export-modules + EXPORT exp + FILE_SET fs DESTINATION "include/cxx/export-modules") + +export(TARGETS export-modules + FILE "${CMAKE_BINARY_DIR}/lib/cmake/export-modules/export-modules-targets.cmake" + CXX_MODULES_DIRECTORY "cxx-modules") diff --git a/Tests/RunCMake/CXXModules/ExportInstallCxxModules-check.cmake b/Tests/RunCMake/CXXModules/ExportInstallCxxModules-check.cmake index 9e83fd895..044b03769 100644 --- a/Tests/RunCMake/CXXModules/ExportInstallCxxModules-check.cmake +++ b/Tests/RunCMake/CXXModules/ExportInstallCxxModules-check.cmake @@ -1,25 +1,25 @@ file(READ "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/Export/eee57a7e91412f1be699e9b63fa9d601/exp.cmake" export_script) -if (NOT export_script MATCHES [[include\("\${CMAKE_CURRENT_LIST_DIR}/cxx-modules/cxx-modules\.cmake"\)]]) +if (NOT export_script MATCHES [[include\("\${CMAKE_CURRENT_LIST_DIR}/cxx-modules/cxx-modules-exp\.cmake"\)]]) list(APPEND RunCMake_TEST_FAILED "Could not find C++ module property script inclusion") endif () -file(READ "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/Export/eee57a7e91412f1be699e9b63fa9d601/cxx-modules/cxx-modules.cmake" trampoline_script) +file(READ "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/Export/eee57a7e91412f1be699e9b63fa9d601/cxx-modules/cxx-modules-exp.cmake" trampoline_script) -if (NOT trampoline_script MATCHES [[file\(GLOB _cmake_cxx_module_includes "\${CMAKE_CURRENT_LIST_DIR}/cxx-modules-\*\.cmake"\)]]) +if (NOT trampoline_script MATCHES [[file\(GLOB _cmake_cxx_module_includes "\${CMAKE_CURRENT_LIST_DIR}/cxx-modules-exp-\*\.cmake"\)]]) list(APPEND RunCMake_TEST_FAILED "Could not find C++ module property per-config script inclusion(s)") endif () set(any_exists 0) foreach (config IN ITEMS noconfig Debug Release RelWithDebInfo MinSizeRel) - if (NOT EXISTS "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/Export/eee57a7e91412f1be699e9b63fa9d601/cxx-modules/cxx-modules-${config}.cmake") + if (NOT EXISTS "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/Export/eee57a7e91412f1be699e9b63fa9d601/cxx-modules/cxx-modules-exp-${config}.cmake") continue () endif () set(any_exists 1) - file(READ "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/Export/eee57a7e91412f1be699e9b63fa9d601/cxx-modules/cxx-modules-${config}.cmake" config_script) + file(READ "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/Export/eee57a7e91412f1be699e9b63fa9d601/cxx-modules/cxx-modules-exp-${config}.cmake" config_script) if (NOT config_script MATCHES "include\\(\"\\\${CMAKE_CURRENT_LIST_DIR}/target-export-name-${config}\\.cmake\"\\)") list(APPEND RunCMake_TEST_FAILED diff --git a/Tests/RunCMake/CXXModules/RunCMakeTest.cmake b/Tests/RunCMake/CXXModules/RunCMakeTest.cmake index fcfa60adc..0ac60e000 100644 --- a/Tests/RunCMake/CXXModules/RunCMakeTest.cmake +++ b/Tests/RunCMake/CXXModules/RunCMakeTest.cmake @@ -88,6 +88,7 @@ run_cmake(InstallBMIGenericArgs) run_cmake(InstallBMIIgnore) run_cmake(ExportBuildCxxModules) +run_cmake(ExportBuildCxxModulesTargets) run_cmake(ExportInstallCxxModules) # Generator-specific tests. @@ -170,7 +171,9 @@ run_cxx_module_test(scan-with-pch) # Tests which use named modules. if ("named" IN_LIST CMake_TEST_MODULE_COMPILATION) run_cxx_module_test(simple) + run_cxx_module_test(vs-without-flags) run_cxx_module_test(library library-static -DBUILD_SHARED_LIBS=OFF) + run_cxx_module_test(unity-build) run_cxx_module_test(object-library) run_cxx_module_test(generated) run_cxx_module_test(deep-chain) @@ -178,6 +181,7 @@ if ("named" IN_LIST CMake_TEST_MODULE_COMPILATION) run_cxx_module_test(non-trivial-collation-order-randomized) run_cxx_module_test(duplicate) set(RunCMake_CXXModules_NO_TEST 1) + run_cxx_module_test(import-from-object) run_cxx_module_test(circular) run_cxx_module_test(try-compile) run_cxx_module_test(try-run) diff --git a/Tests/RunCMake/CXXModules/examples/import-from-object/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/import-from-object/CMakeLists.txt new file mode 100644 index 000000000..e9ec809b7 --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/import-from-object/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.24...3.28) +project(cxx_modules_import_from_object CXX) + +include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake") + +set(CMAKE_CXX_STANDARD 20) + +add_library(a STATIC) +target_sources(a + PUBLIC + FILE_SET CXX_MODULES + FILES + object-a.cxx) + +add_library(b OBJECT object-b.cxx) +target_link_libraries(b PRIVATE a) diff --git a/Tests/RunCMake/CXXModules/examples/import-from-object/object-a.cxx b/Tests/RunCMake/CXXModules/examples/import-from-object/object-a.cxx new file mode 100644 index 000000000..9634a8f51 --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/import-from-object/object-a.cxx @@ -0,0 +1,2 @@ +module; +export module a; diff --git a/Tests/RunCMake/CXXModules/examples/import-from-object/object-b.cxx b/Tests/RunCMake/CXXModules/examples/import-from-object/object-b.cxx new file mode 100644 index 000000000..3b2a80c81 --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/import-from-object/object-b.cxx @@ -0,0 +1 @@ +import a; diff --git a/Tests/RunCMake/CXXModules/examples/scan_properties/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/scan_properties/CMakeLists.txt index 47be1d9c2..110e411da 100644 --- a/Tests/RunCMake/CXXModules/examples/scan_properties/CMakeLists.txt +++ b/Tests/RunCMake/CXXModules/examples/scan_properties/CMakeLists.txt @@ -18,8 +18,10 @@ string(REPLACE "" " -DCMAKE_SCANNED_THIS_SOURCE" set_property(SOURCE always_scan.cxx PROPERTY CXX_SCAN_FOR_MODULES 1) -set_property(SOURCE never_scan.cxx +set_property(SOURCE never_scan.ixx PROPERTY CXX_SCAN_FOR_MODULES 0) +set_property(SOURCE never_scan.ixx + PROPERTY LANGUAGE CXX) add_executable(scans_everything) target_sources(scans_everything @@ -27,7 +29,7 @@ target_sources(scans_everything main.cxx join.cxx always_scan.cxx - never_scan.cxx + never_scan.ixx PRIVATE FILE_SET CXX_MODULES BASE_DIRS @@ -46,7 +48,7 @@ target_sources(no_scan_everything main.cxx join.cxx always_scan.cxx - never_scan.cxx + never_scan.ixx PRIVATE FILE_SET CXX_MODULES BASE_DIRS diff --git a/Tests/RunCMake/CXXModules/examples/scan_properties/never_scan.cxx b/Tests/RunCMake/CXXModules/examples/scan_properties/never_scan.ixx similarity index 100% rename from Tests/RunCMake/CXXModules/examples/scan_properties/never_scan.cxx rename to Tests/RunCMake/CXXModules/examples/scan_properties/never_scan.ixx diff --git a/Tests/RunCMake/CXXModules/examples/unity-build/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/unity-build/CMakeLists.txt new file mode 100644 index 000000000..ce1751dd1 --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/unity-build/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.28) +project(cxx_modules_unity CXX) + +include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake") + +set(CMAKE_UNITY_BUILD 1) + +add_executable(unity) +target_sources(unity + PRIVATE + main.cxx + unity1.cxx + unity2.cxx + PRIVATE + FILE_SET CXX_MODULES + BASE_DIRS + "${CMAKE_CURRENT_SOURCE_DIR}" + FILES + importable.cxx) +target_compile_features(unity PUBLIC cxx_std_20) + +set_property(SOURCE unity1.cxx unity2.cxx + PROPERTY + CXX_SCAN_FOR_MODULES 0) + +add_test(NAME unity COMMAND unity) diff --git a/Tests/RunCMake/CXXModules/examples/unity-build/importable.cxx b/Tests/RunCMake/CXXModules/examples/unity-build/importable.cxx new file mode 100644 index 000000000..148b033ae --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/unity-build/importable.cxx @@ -0,0 +1,10 @@ +module; + +#include "unity.h" + +export module importable; + +export int from_import() +{ + return unity1() + unity2(); +} diff --git a/Tests/RunCMake/CXXModules/examples/unity-build/main.cxx b/Tests/RunCMake/CXXModules/examples/unity-build/main.cxx new file mode 100644 index 000000000..feb38d22e --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/unity-build/main.cxx @@ -0,0 +1,6 @@ +import importable; + +int main(int argc, char* argv[]) +{ + return from_import(); +} diff --git a/Tests/RunCMake/CXXModules/examples/unity-build/unity.h b/Tests/RunCMake/CXXModules/examples/unity-build/unity.h new file mode 100644 index 000000000..4a65a4bb7 --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/unity-build/unity.h @@ -0,0 +1,7 @@ +#ifndef unity_h +#define unity_h + +int unity1(); +int unity2(); + +#endif diff --git a/Tests/RunCMake/CXXModules/examples/unity-build/unity1.cxx b/Tests/RunCMake/CXXModules/examples/unity-build/unity1.cxx new file mode 100644 index 000000000..fd1cbb3ee --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/unity-build/unity1.cxx @@ -0,0 +1,8 @@ +#include "unity.h" + +#define DETECT_UNITY + +int unity1() +{ + return 0; +} diff --git a/Tests/RunCMake/CXXModules/examples/unity-build/unity2.cxx b/Tests/RunCMake/CXXModules/examples/unity-build/unity2.cxx new file mode 100644 index 000000000..0f25cff8c --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/unity-build/unity2.cxx @@ -0,0 +1,10 @@ +#include "unity.h" + +#ifndef DETECT_UNITY +# error "Should have detected a unity build" +#endif + +int unity2() +{ + return 0; +} diff --git a/Tests/RunCMake/CXXModules/examples/vs-without-flags/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/vs-without-flags/CMakeLists.txt new file mode 100644 index 000000000..0d18a669a --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/vs-without-flags/CMakeLists.txt @@ -0,0 +1,22 @@ +cmake_minimum_required(VERSION 3.28) +project(cxx_modules_vs_without_flags CXX) + +include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake") + +set(CMAKE_CXX_STANDARD 23) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) +set(CMAKE_CXX_SCAN_FOR_MODULES ON) + +add_executable(vs_without_flags) +target_sources(vs_without_flags + PRIVATE + main.cxx + PRIVATE + FILE_SET CXX_MODULES + BASE_DIRS + "${CMAKE_CURRENT_SOURCE_DIR}" + FILES + module.cxx) + +add_test(NAME vs_without_flags COMMAND vs_without_flags) diff --git a/Tests/RunCMake/CXXModules/examples/vs-without-flags/main.cxx b/Tests/RunCMake/CXXModules/examples/vs-without-flags/main.cxx new file mode 100644 index 000000000..239ab00e2 --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/vs-without-flags/main.cxx @@ -0,0 +1,6 @@ +import mod; + +int main(int argc, char* argv[]) +{ + return f(); +} diff --git a/Tests/RunCMake/CXXModules/examples/vs-without-flags/module.cxx b/Tests/RunCMake/CXXModules/examples/vs-without-flags/module.cxx new file mode 100644 index 000000000..27a61a6ea --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/vs-without-flags/module.cxx @@ -0,0 +1,6 @@ +export module mod; + +export int f() +{ + return 0; +} diff --git a/Tests/RunCMake/Ninja/LINK_OPTIONSWithNewlines.cmake b/Tests/RunCMake/Ninja/LINK_OPTIONSWithNewlines.cmake new file mode 100644 index 000000000..285966e08 --- /dev/null +++ b/Tests/RunCMake/Ninja/LINK_OPTIONSWithNewlines.cmake @@ -0,0 +1,7 @@ +enable_language(C) + +add_library(hello STATIC hello.c) + +target_link_options(hello PRIVATE "-FLAGS=[ + FLAG1, + FLAG2]") diff --git a/Tests/RunCMake/Ninja/RunCMakeTest.cmake b/Tests/RunCMake/Ninja/RunCMakeTest.cmake index 42ab1d816..13d9620b4 100644 --- a/Tests/RunCMake/Ninja/RunCMakeTest.cmake +++ b/Tests/RunCMake/Ninja/RunCMakeTest.cmake @@ -405,3 +405,5 @@ endfunction() if(CMake_TEST_Qt_version) run_QtAutoMocSkipPch() endif() + +run_cmake(LINK_OPTIONSWithNewlines) diff --git a/Tests/RunCMake/target_link_libraries/ImportedTargetPerConfig.cmake b/Tests/RunCMake/target_link_libraries/ImportedTargetPerConfig.cmake new file mode 100644 index 000000000..a1436179c --- /dev/null +++ b/Tests/RunCMake/target_link_libraries/ImportedTargetPerConfig.cmake @@ -0,0 +1,27 @@ +enable_language(C) +get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(NOT _isMultiConfig AND NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Debug") +endif() + +add_library(StaticImported STATIC IMPORTED) + +# Test with no IMPORTED_CONFIGURATIONS, which works if the +# imported target provides all exact-name configurations +# built by this project. See issue #25515. +set_target_properties(StaticImported PROPERTIES + IMPORTED_LOCATION_DEBUG "a" + IMPORTED_LOCATION_RELEASE "b" + IMPORTED_LOCATION_MINSIZEREL "c" + IMPORTED_LOCATION_RELWITHDEBINFO "d" + ) + +add_library(StaticLib STATIC empty.c) + +# The Xcode generator queries imported targets for system +# include directories, but without any specific config. +set_source_files_properties(empty.c PROPERTIES + INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}" + ) + +target_link_libraries(StaticLib PRIVATE StaticImported) diff --git a/Tests/RunCMake/target_link_libraries/RunCMakeTest.cmake b/Tests/RunCMake/target_link_libraries/RunCMakeTest.cmake index 0e3877aa5..1bcebb822 100644 --- a/Tests/RunCMake/target_link_libraries/RunCMakeTest.cmake +++ b/Tests/RunCMake/target_link_libraries/RunCMakeTest.cmake @@ -25,6 +25,7 @@ run_cmake(CMP0108-NEW-self-link) run_cmake(ImportedTarget) run_cmake(ImportedTargetStub) run_cmake(ImportedTargetFailure) +run_cmake(ImportedTargetPerConfig) run_cmake(MixedSignature) run_cmake(Separate-PRIVATE-LINK_PRIVATE-uses) run_cmake(SharedDepNotTarget) diff --git a/Utilities/IWYU/mapping.imp b/Utilities/IWYU/mapping.imp index 60560307e..e45970d1e 100644 --- a/Utilities/IWYU/mapping.imp +++ b/Utilities/IWYU/mapping.imp @@ -75,10 +75,6 @@ { include: [ "", public, "\"cmsys/FStream.hxx\"", public ] }, { include: [ "", public, "\"cmsys/FStream.hxx\"", public ] }, - { symbol: [ "mode_t", private, "\"cm_sys_stat.h\"", public ] }, - { symbol: [ "S_IWUSR", private, "\"cm_sys_stat.h\"", public ] }, - { symbol: [ "S_IWGRP", private, "\"cm_sys_stat.h\"", public ] }, - { include: [ "", public, "", public ] }, { include: [ "", public, "", public ] }, { include: [ "", public, "", public ] }, diff --git a/Utilities/Scripts/update-zlib.bash b/Utilities/Scripts/update-zlib.bash index e29da888e..5913150f8 100755 --- a/Utilities/Scripts/update-zlib.bash +++ b/Utilities/Scripts/update-zlib.bash @@ -8,7 +8,7 @@ readonly name="zlib" readonly ownership="zlib upstream " readonly subtree="Utilities/cmzlib" readonly repo="https://github.com/madler/zlib.git" -readonly tag="v1.2.12" +readonly tag="v1.2.13" readonly shortlog=false readonly paths=" README diff --git a/Utilities/cmzlib/README b/Utilities/cmzlib/README index 024b79d3d..ba34d1894 100644 --- a/Utilities/cmzlib/README +++ b/Utilities/cmzlib/README @@ -1,6 +1,6 @@ ZLIB DATA COMPRESSION LIBRARY -zlib 1.2.12 is a general purpose data compression library. All the code is +zlib 1.2.13 is a general purpose data compression library. All the code is thread safe. The data format used by the zlib library is described by RFCs (Request for Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 (zlib format), rfc1951 (deflate format) and @@ -31,7 +31,7 @@ Mark Nelson wrote an article about zlib for the Jan. 1997 issue of Dr. Dobb's Journal; a copy of the article is available at http://marknelson.us/1997/01/01/zlib-engine/ . -The changes made in version 1.2.12 are documented in the file ChangeLog. +The changes made in version 1.2.13 are documented in the file ChangeLog. Unsupported third party contributions are provided in directory contrib/ . diff --git a/Utilities/cmzlib/compress.c b/Utilities/cmzlib/compress.c index e2db404ab..2ad5326c1 100644 --- a/Utilities/cmzlib/compress.c +++ b/Utilities/cmzlib/compress.c @@ -19,7 +19,7 @@ memory, Z_BUF_ERROR if there was not enough room in the output buffer, Z_STREAM_ERROR if the level parameter is invalid. */ -int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) +int ZEXPORT compress2(dest, destLen, source, sourceLen, level) Bytef *dest; uLongf *destLen; const Bytef *source; @@ -65,7 +65,7 @@ int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) /* =========================================================================== */ -int ZEXPORT compress (dest, destLen, source, sourceLen) +int ZEXPORT compress(dest, destLen, source, sourceLen) Bytef *dest; uLongf *destLen; const Bytef *source; @@ -78,7 +78,7 @@ int ZEXPORT compress (dest, destLen, source, sourceLen) If the default memLevel or windowBits for deflateInit() is changed, then this function needs to be updated. */ -uLong ZEXPORT compressBound (sourceLen) +uLong ZEXPORT compressBound(sourceLen) uLong sourceLen; { return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + diff --git a/Utilities/cmzlib/crc32.c b/Utilities/cmzlib/crc32.c index a1bdce5c2..f8357b083 100644 --- a/Utilities/cmzlib/crc32.c +++ b/Utilities/cmzlib/crc32.c @@ -98,13 +98,22 @@ # endif #endif +/* If available, use the ARM processor CRC32 instruction. */ +#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) && W == 8 +# define ARMCRC32 +#endif + /* Local functions. */ local z_crc_t multmodp OF((z_crc_t a, z_crc_t b)); local z_crc_t x2nmodp OF((z_off64_t n, unsigned k)); -/* If available, use the ARM processor CRC32 instruction. */ -#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) && W == 8 -# define ARMCRC32 +#if defined(W) && (!defined(ARMCRC32) || defined(DYNAMIC_CRC_TABLE)) + local z_word_t byte_swap OF((z_word_t word)); +#endif + +#if defined(W) && !defined(ARMCRC32) + local z_crc_t crc_word OF((z_word_t data)); + local z_word_t crc_word_big OF((z_word_t data)); #endif #if defined(W) && (!defined(ARMCRC32) || defined(DYNAMIC_CRC_TABLE)) @@ -630,7 +639,7 @@ unsigned long ZEXPORT crc32_z(crc, buf, len) #endif /* DYNAMIC_CRC_TABLE */ /* Pre-condition the CRC */ - crc ^= 0xffffffff; + crc = (~crc) & 0xffffffff; /* Compute the CRC up to a word boundary. */ while (len && ((z_size_t)buf & 7) != 0) { @@ -645,8 +654,8 @@ unsigned long ZEXPORT crc32_z(crc, buf, len) len &= 7; /* Do three interleaved CRCs to realize the throughput of one crc32x - instruction per cycle. Each CRC is calcuated on Z_BATCH words. The three - CRCs are combined into a single CRC after each set of batches. */ + instruction per cycle. Each CRC is calculated on Z_BATCH words. The + three CRCs are combined into a single CRC after each set of batches. */ while (num >= 3 * Z_BATCH) { crc1 = 0; crc2 = 0; @@ -749,7 +758,7 @@ unsigned long ZEXPORT crc32_z(crc, buf, len) #endif /* DYNAMIC_CRC_TABLE */ /* Pre-condition the CRC */ - crc ^= 0xffffffff; + crc = (~crc) & 0xffffffff; #ifdef W @@ -1077,7 +1086,7 @@ uLong ZEXPORT crc32_combine64(crc1, crc2, len2) #ifdef DYNAMIC_CRC_TABLE once(&made, make_crc_table); #endif /* DYNAMIC_CRC_TABLE */ - return multmodp(x2nmodp(len2, 3), crc1) ^ crc2; + return multmodp(x2nmodp(len2, 3), crc1) ^ (crc2 & 0xffffffff); } /* ========================================================================= */ @@ -1086,7 +1095,7 @@ uLong ZEXPORT crc32_combine(crc1, crc2, len2) uLong crc2; z_off_t len2; { - return crc32_combine64(crc1, crc2, len2); + return crc32_combine64(crc1, crc2, (z_off64_t)len2); } /* ========================================================================= */ @@ -1103,14 +1112,14 @@ uLong ZEXPORT crc32_combine_gen64(len2) uLong ZEXPORT crc32_combine_gen(len2) z_off_t len2; { - return crc32_combine_gen64(len2); + return crc32_combine_gen64((z_off64_t)len2); } /* ========================================================================= */ -uLong crc32_combine_op(crc1, crc2, op) +uLong ZEXPORT crc32_combine_op(crc1, crc2, op) uLong crc1; uLong crc2; uLong op; { - return multmodp(op, crc1) ^ crc2; + return multmodp(op, crc1) ^ (crc2 & 0xffffffff); } diff --git a/Utilities/cmzlib/deflate.c b/Utilities/cmzlib/deflate.c index 203220629..92ded869e 100644 --- a/Utilities/cmzlib/deflate.c +++ b/Utilities/cmzlib/deflate.c @@ -52,7 +52,7 @@ #include "deflate.h" const char deflate_copyright[] = - " deflate 1.2.12 Copyright 1995-2022 Jean-loup Gailly and Mark Adler "; + " deflate 1.2.13 Copyright 1995-2022 Jean-loup Gailly and Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot @@ -87,13 +87,7 @@ local void lm_init OF((deflate_state *s)); local void putShortMSB OF((deflate_state *s, uInt b)); local void flush_pending OF((z_streamp strm)); local unsigned read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); -#ifdef ASMV -# pragma message("Assembler code may have bugs -- use at your own risk") - void match_init OF((void)); /* asm code initialization */ - uInt longest_match OF((deflate_state *s, IPos cur_match)); -#else local uInt longest_match OF((deflate_state *s, IPos cur_match)); -#endif #ifdef ZLIB_DEBUG local void check_match OF((deflate_state *s, IPos start, IPos match, @@ -160,7 +154,7 @@ local const config configuration_table[10] = { * characters, so that a running hash key can be computed from the previous * key instead of complete recalculation each time. */ -#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) +#define UPDATE_HASH(s,h,c) (h = (((h) << s->hash_shift) ^ (c)) & s->hash_mask) /* =========================================================================== @@ -191,9 +185,9 @@ local const config configuration_table[10] = { */ #define CLEAR_HASH(s) \ do { \ - s->head[s->hash_size-1] = NIL; \ + s->head[s->hash_size - 1] = NIL; \ zmemzero((Bytef *)s->head, \ - (unsigned)(s->hash_size-1)*sizeof(*s->head)); \ + (unsigned)(s->hash_size - 1)*sizeof(*s->head)); \ } while (0) /* =========================================================================== @@ -285,6 +279,8 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, if (windowBits < 0) { /* suppress zlib wrapper */ wrap = 0; + if (windowBits < -15) + return Z_STREAM_ERROR; windowBits = -windowBits; } #ifdef GZIP @@ -314,7 +310,7 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, s->hash_bits = (uInt)memLevel + 7; s->hash_size = 1 << s->hash_bits; s->hash_mask = s->hash_size - 1; - s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); + s->hash_shift = ((s->hash_bits + MIN_MATCH-1) / MIN_MATCH); s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); @@ -347,11 +343,11 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, * sym_buf value to read moves forward three bytes. From that symbol, up to * 31 bits are written to pending_buf. The closest the written pending_buf * bits gets to the next sym_buf symbol to read is just before the last - * code is written. At that time, 31*(n-2) bits have been written, just - * after 24*(n-2) bits have been consumed from sym_buf. sym_buf starts at - * 8*n bits into pending_buf. (Note that the symbol buffer fills when n-1 + * code is written. At that time, 31*(n - 2) bits have been written, just + * after 24*(n - 2) bits have been consumed from sym_buf. sym_buf starts at + * 8*n bits into pending_buf. (Note that the symbol buffer fills when n - 1 * symbols are written.) The closest the writing gets to what is unread is - * then n+14 bits. Here n is lit_bufsize, which is 16384 by default, and + * then n + 14 bits. Here n is lit_bufsize, which is 16384 by default, and * can range from 128 to 32768. * * Therefore, at a minimum, there are 142 bits of space between what is @@ -397,7 +393,7 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, /* ========================================================================= * Check for a valid deflate stream state. Return 0 if ok, 1 if not. */ -local int deflateStateCheck (strm) +local int deflateStateCheck(strm) z_streamp strm; { deflate_state *s; @@ -420,7 +416,7 @@ local int deflateStateCheck (strm) } /* ========================================================================= */ -int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) +int ZEXPORT deflateSetDictionary(strm, dictionary, dictLength) z_streamp strm; const Bytef *dictionary; uInt dictLength; @@ -489,7 +485,7 @@ int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) } /* ========================================================================= */ -int ZEXPORT deflateGetDictionary (strm, dictionary, dictLength) +int ZEXPORT deflateGetDictionary(strm, dictionary, dictLength) z_streamp strm; Bytef *dictionary; uInt *dictLength; @@ -511,7 +507,7 @@ int ZEXPORT deflateGetDictionary (strm, dictionary, dictLength) } /* ========================================================================= */ -int ZEXPORT deflateResetKeep (strm) +int ZEXPORT deflateResetKeep(strm) z_streamp strm; { deflate_state *s; @@ -549,7 +545,7 @@ int ZEXPORT deflateResetKeep (strm) } /* ========================================================================= */ -int ZEXPORT deflateReset (strm) +int ZEXPORT deflateReset(strm) z_streamp strm; { int ret; @@ -561,7 +557,7 @@ int ZEXPORT deflateReset (strm) } /* ========================================================================= */ -int ZEXPORT deflateSetHeader (strm, head) +int ZEXPORT deflateSetHeader(strm, head) z_streamp strm; gz_headerp head; { @@ -572,7 +568,7 @@ int ZEXPORT deflateSetHeader (strm, head) } /* ========================================================================= */ -int ZEXPORT deflatePending (strm, pending, bits) +int ZEXPORT deflatePending(strm, pending, bits) unsigned *pending; int *bits; z_streamp strm; @@ -586,7 +582,7 @@ int ZEXPORT deflatePending (strm, pending, bits) } /* ========================================================================= */ -int ZEXPORT deflatePrime (strm, bits, value) +int ZEXPORT deflatePrime(strm, bits, value) z_streamp strm; int bits; int value; @@ -681,36 +677,50 @@ int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) } /* ========================================================================= - * For the default windowBits of 15 and memLevel of 8, this function returns - * a close to exact, as well as small, upper bound on the compressed size. - * They are coded as constants here for a reason--if the #define's are - * changed, then this function needs to be changed as well. The return - * value for 15 and 8 only works for those exact settings. + * For the default windowBits of 15 and memLevel of 8, this function returns a + * close to exact, as well as small, upper bound on the compressed size. This + * is an expansion of ~0.03%, plus a small constant. + * + * For any setting other than those defaults for windowBits and memLevel, one + * of two worst case bounds is returned. This is at most an expansion of ~4% or + * ~13%, plus a small constant. * - * For any setting other than those defaults for windowBits and memLevel, - * the value returned is a conservative worst case for the maximum expansion - * resulting from using fixed blocks instead of stored blocks, which deflate - * can emit on compressed data for some combinations of the parameters. + * Both the 0.03% and 4% derive from the overhead of stored blocks. The first + * one is for stored blocks of 16383 bytes (memLevel == 8), whereas the second + * is for stored blocks of 127 bytes (the worst case memLevel == 1). The + * expansion results from five bytes of header for each stored block. * - * This function could be more sophisticated to provide closer upper bounds for - * every combination of windowBits and memLevel. But even the conservative - * upper bound of about 14% expansion does not seem onerous for output buffer - * allocation. + * The larger expansion of 13% results from a window size less than or equal to + * the symbols buffer size (windowBits <= memLevel + 7). In that case some of + * the data being compressed may have slid out of the sliding window, impeding + * a stored block from being emitted. Then the only choice is a fixed or + * dynamic block, where a fixed block limits the maximum expansion to 9 bits + * per 8-bit byte, plus 10 bits for every block. The smallest block size for + * which this can occur is 255 (memLevel == 2). + * + * Shifts are used to approximate divisions, for speed. */ uLong ZEXPORT deflateBound(strm, sourceLen) z_streamp strm; uLong sourceLen; { deflate_state *s; - uLong complen, wraplen; + uLong fixedlen, storelen, wraplen; + + /* upper bound for fixed blocks with 9-bit literals and length 255 + (memLevel == 2, which is the lowest that may not use stored blocks) -- + ~13% overhead plus a small constant */ + fixedlen = sourceLen + (sourceLen >> 3) + (sourceLen >> 8) + + (sourceLen >> 9) + 4; - /* conservative upper bound for compressed data */ - complen = sourceLen + - ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5; + /* upper bound for stored blocks with length 127 (memLevel == 1) -- + ~4% overhead plus a small constant */ + storelen = sourceLen + (sourceLen >> 5) + (sourceLen >> 7) + + (sourceLen >> 11) + 7; - /* if can't get parameters, return conservative bound plus zlib wrapper */ + /* if can't get parameters, return larger bound plus a zlib wrapper */ if (deflateStateCheck(strm)) - return complen + 6; + return (fixedlen > storelen ? fixedlen : storelen) + 6; /* compute wrapper length */ s = strm->state; @@ -747,11 +757,12 @@ uLong ZEXPORT deflateBound(strm, sourceLen) wraplen = 6; } - /* if not default parameters, return conservative bound */ + /* if not default parameters, return one of the conservative bounds */ if (s->w_bits != 15 || s->hash_bits != 8 + 7) - return complen + wraplen; + return (s->w_bits <= s->hash_bits ? fixedlen : storelen) + wraplen; - /* default settings: return tight bound for that case */ + /* default settings: return tight bound for that case -- ~0.03% overhead + plus a small constant */ return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + (sourceLen >> 25) + 13 - 6 + wraplen; } @@ -761,7 +772,7 @@ uLong ZEXPORT deflateBound(strm, sourceLen) * IN assertion: the stream state is correct and there is enough room in * pending_buf. */ -local void putShortMSB (s, b) +local void putShortMSB(s, b) deflate_state *s; uInt b; { @@ -808,7 +819,7 @@ local void flush_pending(strm) } while (0) /* ========================================================================= */ -int ZEXPORT deflate (strm, flush) +int ZEXPORT deflate(strm, flush) z_streamp strm; int flush; { @@ -863,7 +874,7 @@ int ZEXPORT deflate (strm, flush) s->status = BUSY_STATE; if (s->status == INIT_STATE) { /* zlib header */ - uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; + uInt header = (Z_DEFLATED + ((s->w_bits - 8) << 4)) << 8; uInt level_flags; if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) @@ -1123,7 +1134,7 @@ int ZEXPORT deflate (strm, flush) } /* ========================================================================= */ -int ZEXPORT deflateEnd (strm) +int ZEXPORT deflateEnd(strm) z_streamp strm; { int status; @@ -1149,7 +1160,7 @@ int ZEXPORT deflateEnd (strm) * To simplify the source, this is not supported for 16-bit MSDOS (which * doesn't have enough memory anyway to duplicate compression states). */ -int ZEXPORT deflateCopy (dest, source) +int ZEXPORT deflateCopy(dest, source) z_streamp dest; z_streamp source; { @@ -1238,7 +1249,7 @@ local unsigned read_buf(strm, buf, size) /* =========================================================================== * Initialize the "longest match" routines for a new zlib stream */ -local void lm_init (s) +local void lm_init(s) deflate_state *s; { s->window_size = (ulg)2L*s->w_size; @@ -1259,11 +1270,6 @@ local void lm_init (s) s->match_length = s->prev_length = MIN_MATCH-1; s->match_available = 0; s->ins_h = 0; -#ifndef FASTEST -#ifdef ASMV - match_init(); /* initialize the asm code */ -#endif -#endif } #ifndef FASTEST @@ -1276,10 +1282,6 @@ local void lm_init (s) * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 * OUT assertion: the match length is not greater than s->lookahead. */ -#ifndef ASMV -/* For 80x86 and 680x0, an optimized version will be provided in match.asm or - * match.S. The code will be functionally equivalent. - */ local uInt longest_match(s, cur_match) deflate_state *s; IPos cur_match; /* current match */ @@ -1304,10 +1306,10 @@ local uInt longest_match(s, cur_match) */ register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; register ush scan_start = *(ushf*)scan; - register ush scan_end = *(ushf*)(scan+best_len-1); + register ush scan_end = *(ushf*)(scan + best_len - 1); #else register Bytef *strend = s->window + s->strstart + MAX_MATCH; - register Byte scan_end1 = scan[best_len-1]; + register Byte scan_end1 = scan[best_len - 1]; register Byte scan_end = scan[best_len]; #endif @@ -1325,7 +1327,8 @@ local uInt longest_match(s, cur_match) */ if ((uInt)nice_match > s->lookahead) nice_match = (int)s->lookahead; - Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, + "need lookahead"); do { Assert(cur_match < s->strstart, "no future"); @@ -1343,43 +1346,44 @@ local uInt longest_match(s, cur_match) /* This code assumes sizeof(unsigned short) == 2. Do not use * UNALIGNED_OK if your compiler uses a different size. */ - if (*(ushf*)(match+best_len-1) != scan_end || + if (*(ushf*)(match + best_len - 1) != scan_end || *(ushf*)match != scan_start) continue; /* It is not necessary to compare scan[2] and match[2] since they are * always equal when the other bytes match, given that the hash keys * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at - * strstart+3, +5, ... up to strstart+257. We check for insufficient + * strstart + 3, + 5, up to strstart + 257. We check for insufficient * lookahead only every 4th comparison; the 128th check will be made - * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is + * at strstart + 257. If MAX_MATCH-2 is not a multiple of 8, it is * necessary to put more guard bytes at the end of the window, or * to check more often for insufficient lookahead. */ Assert(scan[2] == match[2], "scan[2]?"); scan++, match++; do { - } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + } while (*(ushf*)(scan += 2) == *(ushf*)(match += 2) && + *(ushf*)(scan += 2) == *(ushf*)(match += 2) && + *(ushf*)(scan += 2) == *(ushf*)(match += 2) && + *(ushf*)(scan += 2) == *(ushf*)(match += 2) && scan < strend); /* The funny "do {}" generates better code on most compilers */ - /* Here, scan <= window+strstart+257 */ - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + /* Here, scan <= window + strstart + 257 */ + Assert(scan <= s->window + (unsigned)(s->window_size - 1), + "wild scan"); if (*scan == *match) scan++; - len = (MAX_MATCH - 1) - (int)(strend-scan); + len = (MAX_MATCH - 1) - (int)(strend - scan); scan = strend - (MAX_MATCH-1); #else /* UNALIGNED_OK */ - if (match[best_len] != scan_end || - match[best_len-1] != scan_end1 || - *match != *scan || - *++match != scan[1]) continue; + if (match[best_len] != scan_end || + match[best_len - 1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; - /* The check at best_len-1 can be removed because it will be made + /* The check at best_len - 1 can be removed because it will be made * again later. (This heuristic is not always a win.) * It is not necessary to compare scan[2] and match[2] since they * are always equal when the other bytes match, given that @@ -1389,7 +1393,7 @@ local uInt longest_match(s, cur_match) Assert(*scan == *match, "match[2]?"); /* We check for insufficient lookahead only every 8th comparison; - * the 256th check will be made at strstart+258. + * the 256th check will be made at strstart + 258. */ do { } while (*++scan == *++match && *++scan == *++match && @@ -1398,7 +1402,8 @@ local uInt longest_match(s, cur_match) *++scan == *++match && *++scan == *++match && scan < strend); - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + Assert(scan <= s->window + (unsigned)(s->window_size - 1), + "wild scan"); len = MAX_MATCH - (int)(strend - scan); scan = strend - MAX_MATCH; @@ -1410,9 +1415,9 @@ local uInt longest_match(s, cur_match) best_len = len; if (len >= nice_match) break; #ifdef UNALIGNED_OK - scan_end = *(ushf*)(scan+best_len-1); + scan_end = *(ushf*)(scan + best_len - 1); #else - scan_end1 = scan[best_len-1]; + scan_end1 = scan[best_len - 1]; scan_end = scan[best_len]; #endif } @@ -1422,7 +1427,6 @@ local uInt longest_match(s, cur_match) if ((uInt)best_len <= s->lookahead) return (uInt)best_len; return s->lookahead; } -#endif /* ASMV */ #else /* FASTEST */ @@ -1443,7 +1447,8 @@ local uInt longest_match(s, cur_match) */ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); - Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, + "need lookahead"); Assert(cur_match < s->strstart, "no future"); @@ -1453,7 +1458,7 @@ local uInt longest_match(s, cur_match) */ if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; - /* The check at best_len-1 can be removed because it will be made + /* The check at best_len - 1 can be removed because it will be made * again later. (This heuristic is not always a win.) * It is not necessary to compare scan[2] and match[2] since they * are always equal when the other bytes match, given that @@ -1463,7 +1468,7 @@ local uInt longest_match(s, cur_match) Assert(*scan == *match, "match[2]?"); /* We check for insufficient lookahead only every 8th comparison; - * the 256th check will be made at strstart+258. + * the 256th check will be made at strstart + 258. */ do { } while (*++scan == *++match && *++scan == *++match && @@ -1472,7 +1477,7 @@ local uInt longest_match(s, cur_match) *++scan == *++match && *++scan == *++match && scan < strend); - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + Assert(scan <= s->window + (unsigned)(s->window_size - 1), "wild scan"); len = MAX_MATCH - (int)(strend - scan); @@ -1508,7 +1513,7 @@ local void check_match(s, start, match, length) z_error("invalid match"); } if (z_verbose > 1) { - fprintf(stderr,"\\[%d,%d]", start-match, length); + fprintf(stderr,"\\[%d,%d]", start - match, length); do { putc(s->window[start++], stderr); } while (--length != 0); } } @@ -1554,9 +1559,9 @@ local void fill_window(s) /* If the window is almost full and there is insufficient lookahead, * move the upper half to the lower one to make room in the upper half. */ - if (s->strstart >= wsize+MAX_DIST(s)) { + if (s->strstart >= wsize + MAX_DIST(s)) { - zmemcpy(s->window, s->window+wsize, (unsigned)wsize - more); + zmemcpy(s->window, s->window + wsize, (unsigned)wsize - more); s->match_start -= wsize; s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ s->block_start -= (long) wsize; @@ -1687,7 +1692,7 @@ local void fill_window(s) * * deflate_stored() is written to minimize the number of times an input byte is * copied. It is most efficient with large input and output buffers, which - * maximizes the opportunites to have a single copy from next_in to next_out. + * maximizes the opportunities to have a single copy from next_in to next_out. */ local block_state deflate_stored(s, flush) deflate_state *s; @@ -1897,7 +1902,7 @@ local block_state deflate_fast(s, flush) if (s->lookahead == 0) break; /* flush the current block */ } - /* Insert the string window[strstart .. strstart+2] in the + /* Insert the string window[strstart .. strstart + 2] in the * dictionary, and set hash_head to the head of the hash chain: */ hash_head = NIL; @@ -1945,7 +1950,7 @@ local block_state deflate_fast(s, flush) s->strstart += s->match_length; s->match_length = 0; s->ins_h = s->window[s->strstart]; - UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); + UPDATE_HASH(s, s->ins_h, s->window[s->strstart + 1]); #if MIN_MATCH != 3 Call UPDATE_HASH() MIN_MATCH-3 more times #endif @@ -1956,7 +1961,7 @@ local block_state deflate_fast(s, flush) } else { /* No match, output a literal byte */ Tracevv((stderr,"%c", s->window[s->strstart])); - _tr_tally_lit (s, s->window[s->strstart], bflush); + _tr_tally_lit(s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; } @@ -2000,7 +2005,7 @@ local block_state deflate_slow(s, flush) if (s->lookahead == 0) break; /* flush the current block */ } - /* Insert the string window[strstart .. strstart+2] in the + /* Insert the string window[strstart .. strstart + 2] in the * dictionary, and set hash_head to the head of the hash chain: */ hash_head = NIL; @@ -2042,17 +2047,17 @@ local block_state deflate_slow(s, flush) uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; /* Do not insert strings in hash table beyond this. */ - check_match(s, s->strstart-1, s->prev_match, s->prev_length); + check_match(s, s->strstart - 1, s->prev_match, s->prev_length); - _tr_tally_dist(s, s->strstart -1 - s->prev_match, + _tr_tally_dist(s, s->strstart - 1 - s->prev_match, s->prev_length - MIN_MATCH, bflush); /* Insert in hash table all strings up to the end of the match. - * strstart-1 and strstart are already inserted. If there is not + * strstart - 1 and strstart are already inserted. If there is not * enough lookahead, the last two strings are not inserted in * the hash table. */ - s->lookahead -= s->prev_length-1; + s->lookahead -= s->prev_length - 1; s->prev_length -= 2; do { if (++s->strstart <= max_insert) { @@ -2070,8 +2075,8 @@ local block_state deflate_slow(s, flush) * single literal. If there was a match but the current match * is longer, truncate the previous match to a single literal. */ - Tracevv((stderr,"%c", s->window[s->strstart-1])); - _tr_tally_lit(s, s->window[s->strstart-1], bflush); + Tracevv((stderr,"%c", s->window[s->strstart - 1])); + _tr_tally_lit(s, s->window[s->strstart - 1], bflush); if (bflush) { FLUSH_BLOCK_ONLY(s, 0); } @@ -2089,8 +2094,8 @@ local block_state deflate_slow(s, flush) } Assert (flush != Z_NO_FLUSH, "no flush?"); if (s->match_available) { - Tracevv((stderr,"%c", s->window[s->strstart-1])); - _tr_tally_lit(s, s->window[s->strstart-1], bflush); + Tracevv((stderr,"%c", s->window[s->strstart - 1])); + _tr_tally_lit(s, s->window[s->strstart - 1], bflush); s->match_available = 0; } s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; @@ -2147,7 +2152,8 @@ local block_state deflate_rle(s, flush) if (s->match_length > s->lookahead) s->match_length = s->lookahead; } - Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan"); + Assert(scan <= s->window + (uInt)(s->window_size - 1), + "wild scan"); } /* Emit match if have run of MIN_MATCH or longer, else emit literal */ @@ -2162,7 +2168,7 @@ local block_state deflate_rle(s, flush) } else { /* No match, output a literal byte */ Tracevv((stderr,"%c", s->window[s->strstart])); - _tr_tally_lit (s, s->window[s->strstart], bflush); + _tr_tally_lit(s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; } @@ -2202,7 +2208,7 @@ local block_state deflate_huff(s, flush) /* Output a literal byte */ s->match_length = 0; Tracevv((stderr,"%c", s->window[s->strstart])); - _tr_tally_lit (s, s->window[s->strstart], bflush); + _tr_tally_lit(s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; if (bflush) FLUSH_BLOCK(s, 0); diff --git a/Utilities/cmzlib/deflate.h b/Utilities/cmzlib/deflate.h index 17c226113..1a06cd5f2 100644 --- a/Utilities/cmzlib/deflate.h +++ b/Utilities/cmzlib/deflate.h @@ -329,8 +329,8 @@ void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf, # define _tr_tally_dist(s, distance, length, flush) \ { uch len = (uch)(length); \ ush dist = (ush)(distance); \ - s->sym_buf[s->sym_next++] = dist; \ - s->sym_buf[s->sym_next++] = dist >> 8; \ + s->sym_buf[s->sym_next++] = (uch)dist; \ + s->sym_buf[s->sym_next++] = (uch)(dist >> 8); \ s->sym_buf[s->sym_next++] = len; \ dist--; \ s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ diff --git a/Utilities/cmzlib/gzlib.c b/Utilities/cmzlib/gzlib.c index dddaf2687..55da46a45 100644 --- a/Utilities/cmzlib/gzlib.c +++ b/Utilities/cmzlib/gzlib.c @@ -30,7 +30,7 @@ local gzFile gz_open OF((const void *, int, const char *)); The gz_strwinerror function does not change the current setting of GetLastError. */ -char ZLIB_INTERNAL *gz_strwinerror (error) +char ZLIB_INTERNAL *gz_strwinerror(error) DWORD error; { static char buf[1024]; diff --git a/Utilities/cmzlib/gzread.c b/Utilities/cmzlib/gzread.c index e3519e6d0..eaa552336 100644 --- a/Utilities/cmzlib/gzread.c +++ b/Utilities/cmzlib/gzread.c @@ -157,11 +157,9 @@ local int gz_look(state) the output buffer is larger than the input buffer, which also assures space for gzungetc() */ state->x.next = state->out; - if (strm->avail_in) { - memcpy(state->x.next, strm->next_in, strm->avail_in); - state->x.have = strm->avail_in; - strm->avail_in = 0; - } + memcpy(state->x.next, strm->next_in, strm->avail_in); + state->x.have = strm->avail_in; + strm->avail_in = 0; state->how = COPY; state->direct = 1; return 0; diff --git a/Utilities/cmzlib/gzwrite.c b/Utilities/cmzlib/gzwrite.c index 33f494969..16d4a22b6 100644 --- a/Utilities/cmzlib/gzwrite.c +++ b/Utilities/cmzlib/gzwrite.c @@ -480,7 +480,7 @@ int ZEXPORTVA gzprintf(gzFile file, const char *format, ...) #else /* !STDC && !Z_HAVE_STDARG_H */ /* -- see zlib.h -- */ -int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, +int ZEXPORTVA gzprintf(file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) gzFile file; const char *format; diff --git a/Utilities/cmzlib/inflate.c b/Utilities/cmzlib/inflate.c index 7be8c6366..8acbef44e 100644 --- a/Utilities/cmzlib/inflate.c +++ b/Utilities/cmzlib/inflate.c @@ -168,6 +168,8 @@ int windowBits; /* extract wrap request from windowBits parameter */ if (windowBits < 0) { + if (windowBits < -15) + return Z_STREAM_ERROR; wrap = 0; windowBits = -windowBits; } @@ -764,8 +766,9 @@ int flush; if (copy > have) copy = have; if (copy) { if (state->head != Z_NULL && - state->head->extra != Z_NULL) { - len = state->head->extra_len - state->length; + state->head->extra != Z_NULL && + (len = state->head->extra_len - state->length) < + state->head->extra_max) { zmemcpy(state->head->extra + len, next, len + copy > state->head->extra_max ? state->head->extra_max - len : copy); diff --git a/Utilities/cmzlib/inftrees.c b/Utilities/cmzlib/inftrees.c index 09462a740..57d2793be 100644 --- a/Utilities/cmzlib/inftrees.c +++ b/Utilities/cmzlib/inftrees.c @@ -9,7 +9,7 @@ #define MAXBITS 15 const char inflate_copyright[] = - " inflate 1.2.12 Copyright 1995-2022 Mark Adler "; + " inflate 1.2.13 Copyright 1995-2022 Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot @@ -62,7 +62,7 @@ unsigned short FAR *work; 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; static const unsigned short lext[31] = { /* Length codes 257..285 extra */ 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, - 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 199, 202}; + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 194, 65}; static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, diff --git a/Utilities/cmzlib/inftrees.h b/Utilities/cmzlib/inftrees.h index baa53a0b1..f53665311 100644 --- a/Utilities/cmzlib/inftrees.h +++ b/Utilities/cmzlib/inftrees.h @@ -38,7 +38,7 @@ typedef struct { /* Maximum size of the dynamic table. The maximum number of code structures is 1444, which is the sum of 852 for literal/length codes and 592 for distance codes. These values were found by exhaustive searches using the program - examples/enough.c found in the zlib distribtution. The arguments to that + examples/enough.c found in the zlib distribution. The arguments to that program are the number of symbols, the initial root table size, and the maximum bit length of a code. "enough 286 9 15" for literal/length codes returns returns 852, and "enough 30 6 15" for distance codes returns 592. diff --git a/Utilities/cmzlib/trees.c b/Utilities/cmzlib/trees.c index f73fd99c3..5f305c472 100644 --- a/Utilities/cmzlib/trees.c +++ b/Utilities/cmzlib/trees.c @@ -193,7 +193,7 @@ local void send_bits(s, value, length) s->bits_sent += (ulg)length; /* If not enough room in bi_buf, use (valid) bits from bi_buf and - * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) + * (16 - bi_valid) bits from value, leaving (width - (16 - bi_valid)) * unused bits in value. */ if (s->bi_valid > (int)Buf_size - length) { @@ -256,7 +256,7 @@ local void tr_static_init() length = 0; for (code = 0; code < LENGTH_CODES-1; code++) { base_length[code] = length; - for (n = 0; n < (1< dist code (0..29) */ dist = 0; for (code = 0 ; code < 16; code++) { base_dist[code] = dist; - for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ for ( ; code < D_CODES; code++) { base_dist[code] = dist << 7; - for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + for (n = 0; n < (1 << (extra_dbits[code] - 7)); n++) { _dist_code[256 + dist++] = (uch)code; } } - Assert (dist == 256, "tr_static_init: 256+dist != 512"); + Assert (dist == 256, "tr_static_init: 256 + dist != 512"); /* Construct the codes of the static literal tree */ for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; @@ -312,7 +312,7 @@ local void tr_static_init() } /* =========================================================================== - * Genererate the file trees.h describing the static trees. + * Generate the file trees.h describing the static trees. */ #ifdef GEN_TREES_H # ifndef ZLIB_DEBUG @@ -321,7 +321,7 @@ local void tr_static_init() # define SEPARATOR(i, last, width) \ ((i) == (last)? "\n};\n\n" : \ - ((i) % (width) == (width)-1 ? ",\n" : ", ")) + ((i) % (width) == (width) - 1 ? ",\n" : ", ")) void gen_trees_header() { @@ -458,7 +458,7 @@ local void pqdownheap(s, tree, k) while (j <= s->heap_len) { /* Set j to the smallest of the two sons: */ if (j < s->heap_len && - smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { + smaller(tree, s->heap[j + 1], s->heap[j], s->depth)) { j++; } /* Exit if v is smaller than both sons */ @@ -507,7 +507,7 @@ local void gen_bitlen(s, desc) */ tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ - for (h = s->heap_max+1; h < HEAP_SIZE; h++) { + for (h = s->heap_max + 1; h < HEAP_SIZE; h++) { n = s->heap[h]; bits = tree[tree[n].Dad].Len + 1; if (bits > max_length) bits = max_length, overflow++; @@ -518,7 +518,7 @@ local void gen_bitlen(s, desc) s->bl_count[bits]++; xbits = 0; - if (n >= base) xbits = extra[n-base]; + if (n >= base) xbits = extra[n - base]; f = tree[n].Freq; s->opt_len += (ulg)f * (unsigned)(bits + xbits); if (stree) s->static_len += (ulg)f * (unsigned)(stree[n].Len + xbits); @@ -530,10 +530,10 @@ local void gen_bitlen(s, desc) /* Find the first bit length which could increase: */ do { - bits = max_length-1; + bits = max_length - 1; while (s->bl_count[bits] == 0) bits--; - s->bl_count[bits]--; /* move one leaf down the tree */ - s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits + 1] += 2; /* move one overflow item as its brother */ s->bl_count[max_length]--; /* The brother of the overflow item also moves one step up, * but this does not affect bl_count[max_length] @@ -569,7 +569,7 @@ local void gen_bitlen(s, desc) * OUT assertion: the field code is set for all tree elements of non * zero code length. */ -local void gen_codes (tree, max_code, bl_count) +local void gen_codes(tree, max_code, bl_count) ct_data *tree; /* the tree to decorate */ int max_code; /* largest code with non zero frequency */ ushf *bl_count; /* number of codes at each bit length */ @@ -583,13 +583,13 @@ local void gen_codes (tree, max_code, bl_count) * without bit reversal. */ for (bits = 1; bits <= MAX_BITS; bits++) { - code = (code + bl_count[bits-1]) << 1; + code = (code + bl_count[bits - 1]) << 1; next_code[bits] = (ush)code; } /* Check that the bit counts in bl_count are consistent. The last code * must be all ones. */ - Assert (code + bl_count[MAX_BITS]-1 == (1<heap_len = 0, s->heap_max = HEAP_SIZE; @@ -652,7 +652,7 @@ local void build_tree(s, desc) } desc->max_code = max_code; - /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + /* The elements heap[heap_len/2 + 1 .. heap_len] are leaves of the tree, * establish sub-heaps of increasing lengths: */ for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); @@ -700,7 +700,7 @@ local void build_tree(s, desc) * Scan a literal or distance tree to determine the frequencies of the codes * in the bit length tree. */ -local void scan_tree (s, tree, max_code) +local void scan_tree(s, tree, max_code) deflate_state *s; ct_data *tree; /* the tree to be scanned */ int max_code; /* and its largest code of non zero frequency */ @@ -714,10 +714,10 @@ local void scan_tree (s, tree, max_code) int min_count = 4; /* min repeat count */ if (nextlen == 0) max_count = 138, min_count = 3; - tree[max_code+1].Len = (ush)0xffff; /* guard */ + tree[max_code + 1].Len = (ush)0xffff; /* guard */ for (n = 0; n <= max_code; n++) { - curlen = nextlen; nextlen = tree[n+1].Len; + curlen = nextlen; nextlen = tree[n + 1].Len; if (++count < max_count && curlen == nextlen) { continue; } else if (count < min_count) { @@ -745,7 +745,7 @@ local void scan_tree (s, tree, max_code) * Send a literal or distance tree in compressed form, using the codes in * bl_tree. */ -local void send_tree (s, tree, max_code) +local void send_tree(s, tree, max_code) deflate_state *s; ct_data *tree; /* the tree to be scanned */ int max_code; /* and its largest code of non zero frequency */ @@ -758,11 +758,11 @@ local void send_tree (s, tree, max_code) int max_count = 7; /* max repeat count */ int min_count = 4; /* min repeat count */ - /* tree[max_code+1].Len = -1; */ /* guard already set */ + /* tree[max_code + 1].Len = -1; */ /* guard already set */ if (nextlen == 0) max_count = 138, min_count = 3; for (n = 0; n <= max_code; n++) { - curlen = nextlen; nextlen = tree[n+1].Len; + curlen = nextlen; nextlen = tree[n + 1].Len; if (++count < max_count && curlen == nextlen) { continue; } else if (count < min_count) { @@ -773,13 +773,13 @@ local void send_tree (s, tree, max_code) send_code(s, curlen, s->bl_tree); count--; } Assert(count >= 3 && count <= 6, " 3_6?"); - send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count - 3, 2); } else if (count <= 10) { - send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count - 3, 3); } else { - send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count - 11, 7); } count = 0; prevlen = curlen; if (nextlen == 0) { @@ -807,8 +807,8 @@ local int build_bl_tree(s) /* Build the bit length tree: */ build_tree(s, (tree_desc *)(&(s->bl_desc))); - /* opt_len now includes the length of the tree representations, except - * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + /* opt_len now includes the length of the tree representations, except the + * lengths of the bit lengths codes and the 5 + 5 + 4 bits for the counts. */ /* Determine the number of bit length codes to send. The pkzip format @@ -819,7 +819,7 @@ local int build_bl_tree(s) if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; } /* Update opt_len to include the bit length tree and counts */ - s->opt_len += 3*((ulg)max_blindex+1) + 5+5+4; + s->opt_len += 3*((ulg)max_blindex + 1) + 5 + 5 + 4; Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", s->opt_len, s->static_len)); @@ -841,19 +841,19 @@ local void send_all_trees(s, lcodes, dcodes, blcodes) Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, "too many codes"); Tracev((stderr, "\nbl counts: ")); - send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ - send_bits(s, dcodes-1, 5); - send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ + send_bits(s, lcodes - 257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes - 1, 5); + send_bits(s, blcodes - 4, 4); /* not -3 as stated in appnote.txt */ for (rank = 0; rank < blcodes; rank++) { Tracev((stderr, "\nbl code %2d ", bl_order[rank])); send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); } Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); - send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ + send_tree(s, (ct_data *)s->dyn_ltree, lcodes - 1); /* literal tree */ Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); - send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ + send_tree(s, (ct_data *)s->dyn_dtree, dcodes - 1); /* distance tree */ Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); } @@ -866,7 +866,7 @@ void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last) ulg stored_len; /* length of input block */ int last; /* one if this is the last block for a file */ { - send_bits(s, (STORED_BLOCK<<1)+last, 3); /* send block type */ + send_bits(s, (STORED_BLOCK<<1) + last, 3); /* send block type */ bi_windup(s); /* align on byte boundary */ put_short(s, (ush)stored_len); put_short(s, (ush)~stored_len); @@ -877,7 +877,7 @@ void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last) s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; s->compressed_len += (stored_len + 4) << 3; s->bits_sent += 2*16; - s->bits_sent += stored_len<<3; + s->bits_sent += stored_len << 3; #endif } @@ -943,14 +943,17 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) max_blindex = build_bl_tree(s); /* Determine the best encoding. Compute the block lengths in bytes. */ - opt_lenb = (s->opt_len+3+7)>>3; - static_lenb = (s->static_len+3+7)>>3; + opt_lenb = (s->opt_len + 3 + 7) >> 3; + static_lenb = (s->static_len + 3 + 7) >> 3; Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, s->sym_next / 3)); - if (static_lenb <= opt_lenb) opt_lenb = static_lenb; +#ifndef FORCE_STATIC + if (static_lenb <= opt_lenb || s->strategy == Z_FIXED) +#endif + opt_lenb = static_lenb; } else { Assert(buf != (char*)0, "lost buf"); @@ -960,7 +963,7 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) #ifdef FORCE_STORED if (buf != (char*)0) { /* force stored block */ #else - if (stored_len+4 <= opt_lenb && buf != (char*)0) { + if (stored_len + 4 <= opt_lenb && buf != (char*)0) { /* 4: two words for the lengths */ #endif /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. @@ -971,21 +974,17 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) */ _tr_stored_block(s, buf, stored_len, last); -#ifdef FORCE_STATIC - } else if (static_lenb >= 0) { /* force static trees */ -#else - } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) { -#endif - send_bits(s, (STATIC_TREES<<1)+last, 3); + } else if (static_lenb == opt_lenb) { + send_bits(s, (STATIC_TREES<<1) + last, 3); compress_block(s, (const ct_data *)static_ltree, (const ct_data *)static_dtree); #ifdef ZLIB_DEBUG s->compressed_len += 3 + s->static_len; #endif } else { - send_bits(s, (DYN_TREES<<1)+last, 3); - send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, - max_blindex+1); + send_bits(s, (DYN_TREES<<1) + last, 3); + send_all_trees(s, s->l_desc.max_code + 1, s->d_desc.max_code + 1, + max_blindex + 1); compress_block(s, (const ct_data *)s->dyn_ltree, (const ct_data *)s->dyn_dtree); #ifdef ZLIB_DEBUG @@ -1004,22 +1003,22 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) s->compressed_len += 7; /* align on byte boundary */ #endif } - Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, - s->compressed_len-7*last)); + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len >> 3, + s->compressed_len - 7*last)); } /* =========================================================================== * Save the match info and tally the frequency counts. Return true if * the current block must be flushed. */ -int ZLIB_INTERNAL _tr_tally (s, dist, lc) +int ZLIB_INTERNAL _tr_tally(s, dist, lc) deflate_state *s; unsigned dist; /* distance of matched string */ - unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ + unsigned lc; /* match length - MIN_MATCH or unmatched char (dist==0) */ { - s->sym_buf[s->sym_next++] = dist; - s->sym_buf[s->sym_next++] = dist >> 8; - s->sym_buf[s->sym_next++] = lc; + s->sym_buf[s->sym_next++] = (uch)dist; + s->sym_buf[s->sym_next++] = (uch)(dist >> 8); + s->sym_buf[s->sym_next++] = (uch)lc; if (dist == 0) { /* lc is the unmatched char */ s->dyn_ltree[lc].Freq++; @@ -1031,7 +1030,7 @@ int ZLIB_INTERNAL _tr_tally (s, dist, lc) (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); - s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; + s->dyn_ltree[_length_code[lc] + LITERALS + 1].Freq++; s->dyn_dtree[d_code(dist)].Freq++; } return (s->sym_next == s->sym_end); @@ -1061,7 +1060,7 @@ local void compress_block(s, ltree, dtree) } else { /* Here, lc is the match length - MIN_MATCH */ code = _length_code[lc]; - send_code(s, code+LITERALS+1, ltree); /* send the length code */ + send_code(s, code + LITERALS + 1, ltree); /* send length code */ extra = extra_lbits[code]; if (extra != 0) { lc -= base_length[code]; @@ -1177,6 +1176,6 @@ local void bi_windup(s) s->bi_buf = 0; s->bi_valid = 0; #ifdef ZLIB_DEBUG - s->bits_sent = (s->bits_sent+7) & ~7; + s->bits_sent = (s->bits_sent + 7) & ~7; #endif } diff --git a/Utilities/cmzlib/uncompr.c b/Utilities/cmzlib/uncompr.c index f03a1a865..f9532f46c 100644 --- a/Utilities/cmzlib/uncompr.c +++ b/Utilities/cmzlib/uncompr.c @@ -24,7 +24,7 @@ Z_DATA_ERROR if the input data was corrupted, including if the input data is an incomplete zlib stream. */ -int ZEXPORT uncompress2 (dest, destLen, source, sourceLen) +int ZEXPORT uncompress2(dest, destLen, source, sourceLen) Bytef *dest; uLongf *destLen; const Bytef *source; @@ -83,7 +83,7 @@ int ZEXPORT uncompress2 (dest, destLen, source, sourceLen) err; } -int ZEXPORT uncompress (dest, destLen, source, sourceLen) +int ZEXPORT uncompress(dest, destLen, source, sourceLen) Bytef *dest; uLongf *destLen; const Bytef *source; diff --git a/Utilities/cmzlib/zconf.h b/Utilities/cmzlib/zconf.h index 1790072cf..fe4ec592a 100644 --- a/Utilities/cmzlib/zconf.h +++ b/Utilities/cmzlib/zconf.h @@ -40,6 +40,9 @@ # define crc32 z_crc32 # define crc32_combine z_crc32_combine # define crc32_combine64 z_crc32_combine64 +# define crc32_combine_gen z_crc32_combine_gen +# define crc32_combine_gen64 z_crc32_combine_gen64 +# define crc32_combine_op z_crc32_combine_op # define crc32_z z_crc32_z # define deflate z_deflate # define deflateBound z_deflateBound @@ -351,6 +354,9 @@ # ifdef FAR # undef FAR # endif +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif # include /* No need for _export, use ZLIB.DEF instead. */ /* For complete Windows compatibility, use WINAPI, not __stdcall. */ @@ -469,11 +475,18 @@ typedef uLong FAR uLongf; # undef _LARGEFILE64_SOURCE #endif -#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H) -# define Z_HAVE_UNISTD_H +#ifndef Z_HAVE_UNISTD_H +# ifdef __WATCOMC__ +# define Z_HAVE_UNISTD_H +# endif +#endif +#ifndef Z_HAVE_UNISTD_H +# if defined(_LARGEFILE64_SOURCE) && !defined(_WIN32) +# define Z_HAVE_UNISTD_H +# endif #endif #ifndef Z_SOLO -# if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) +# if defined(Z_HAVE_UNISTD_H) # include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ # ifdef VMS # include /* for off_t */ diff --git a/Utilities/cmzlib/zlib.h b/Utilities/cmzlib/zlib.h index 3764e8577..808ae6849 100644 --- a/Utilities/cmzlib/zlib.h +++ b/Utilities/cmzlib/zlib.h @@ -1,5 +1,5 @@ /* zlib.h -- interface of the 'zlib' general purpose compression library - version 1.2.12, March 11th, 2022 + version 1.2.13, October 13th, 2022 Copyright (C) 1995-2022 Jean-loup Gailly and Mark Adler @@ -37,11 +37,11 @@ extern "C" { #endif -#define ZLIB_VERSION "1.2.12" -#define ZLIB_VERNUM 0x12c0 +#define ZLIB_VERSION "1.2.13" +#define ZLIB_VERNUM 0x12d0 #define ZLIB_VER_MAJOR 1 #define ZLIB_VER_MINOR 2 -#define ZLIB_VER_REVISION 12 +#define ZLIB_VER_REVISION 13 #define ZLIB_VER_SUBREVISION 0 /* @@ -276,7 +276,7 @@ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); == 0), or after each call of deflate(). If deflate returns Z_OK and with zero avail_out, it must be called again after making room in the output buffer because there might be more output pending. See deflatePending(), - which can be used if desired to determine whether or not there is more ouput + which can be used if desired to determine whether or not there is more output in that case. Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to @@ -660,7 +660,7 @@ ZEXTERN int ZEXPORT deflateGetDictionary OF((z_streamp strm, to dictionary. dictionary must have enough space, where 32768 bytes is always enough. If deflateGetDictionary() is called with dictionary equal to Z_NULL, then only the dictionary length is returned, and nothing is copied. - Similary, if dictLength is Z_NULL, then it is not set. + Similarly, if dictLength is Z_NULL, then it is not set. deflateGetDictionary() may return a length less than the window size, even when more than the window size in input has been provided. It may return up @@ -915,7 +915,7 @@ ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm, to dictionary. dictionary must have enough space, where 32768 bytes is always enough. If inflateGetDictionary() is called with dictionary equal to Z_NULL, then only the dictionary length is returned, and nothing is copied. - Similary, if dictLength is Z_NULL, then it is not set. + Similarly, if dictLength is Z_NULL, then it is not set. inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the stream state is inconsistent. @@ -1437,12 +1437,12 @@ ZEXTERN z_size_t ZEXPORT gzfread OF((voidp buf, z_size_t size, z_size_t nitems, In the event that the end of file is reached and only a partial item is available at the end, i.e. the remaining uncompressed data length is not a - multiple of size, then the final partial item is nevetheless read into buf + multiple of size, then the final partial item is nevertheless read into buf and the end-of-file flag is set. The length of the partial item read is not provided, but could be inferred from the result of gztell(). This behavior is the same as the behavior of fread() implementations in common libraries, but it prevents the direct use of gzfread() to read a concurrently written - file, reseting and retrying on end-of-file, when size is not 1. + file, resetting and retrying on end-of-file, when size is not 1. */ ZEXTERN int ZEXPORT gzwrite OF((gzFile file, voidpc buf, unsigned len)); @@ -1931,7 +1931,7 @@ ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp)); ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table OF((void)); ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int)); ZEXTERN int ZEXPORT inflateValidate OF((z_streamp, int)); -ZEXTERN unsigned long ZEXPORT inflateCodesUsed OF ((z_streamp)); +ZEXTERN unsigned long ZEXPORT inflateCodesUsed OF((z_streamp)); ZEXTERN int ZEXPORT inflateResetKeep OF((z_streamp)); ZEXTERN int ZEXPORT deflateResetKeep OF((z_streamp)); #if defined(_WIN32) && !defined(Z_SOLO) diff --git a/Utilities/cmzlib/zutil.c b/Utilities/cmzlib/zutil.c index dcab28a0d..9543ae825 100644 --- a/Utilities/cmzlib/zutil.c +++ b/Utilities/cmzlib/zutil.c @@ -61,9 +61,11 @@ uLong ZEXPORT zlibCompileFlags() #ifdef ZLIB_DEBUG flags += 1 << 8; #endif + /* #if defined(ASMV) || defined(ASMINF) flags += 1 << 9; #endif + */ #ifdef ZLIB_WINAPI flags += 1 << 10; #endif @@ -119,7 +121,7 @@ uLong ZEXPORT zlibCompileFlags() # endif int ZLIB_INTERNAL z_verbose = verbose; -void ZLIB_INTERNAL z_error (m) +void ZLIB_INTERNAL z_error(m) char *m; { fprintf(stderr, "%s\n", m); @@ -214,7 +216,7 @@ local ptr_table table[MAX_PTR]; * a protected system like OS/2. Use Microsoft C instead. */ -voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size) +voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, unsigned size) { voidpf buf; ulg bsize = (ulg)items*size; @@ -240,7 +242,7 @@ voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size) return buf; } -void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) +void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) { int n; @@ -277,13 +279,13 @@ void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) # define _hfree hfree #endif -voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, uInt items, uInt size) +voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, uInt items, uInt size) { (void)opaque; return _halloc((long)items, size); } -void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) +void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) { (void)opaque; _hfree(ptr); @@ -302,7 +304,7 @@ extern voidp calloc OF((uInt items, uInt size)); extern void free OF((voidpf ptr)); #endif -voidpf ZLIB_INTERNAL zcalloc (opaque, items, size) +voidpf ZLIB_INTERNAL zcalloc(opaque, items, size) voidpf opaque; unsigned items; unsigned size; @@ -312,7 +314,7 @@ voidpf ZLIB_INTERNAL zcalloc (opaque, items, size) (voidpf)calloc(items, size); } -void ZLIB_INTERNAL zcfree (opaque, ptr) +void ZLIB_INTERNAL zcfree(opaque, ptr) voidpf opaque; voidpf ptr; { diff --git a/Utilities/cmzlib/zutil.h b/Utilities/cmzlib/zutil.h index 824f3624f..8939d1d17 100644 --- a/Utilities/cmzlib/zutil.h +++ b/Utilities/cmzlib/zutil.h @@ -199,6 +199,7 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0) ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine_gen64 OF((z_off_t)); #endif /* common defaults */