diff options
110 files changed, 1409 insertions, 213 deletions
diff --git a/.clang-tidy b/.clang-tidy index a86f39acff..1e9b78abf8 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -33,6 +33,7 @@ readability-*,\ -readability-redundant-member-init,\ -readability-suspicious-call-argument,\ -readability-uppercase-literal-suffix,\ +cmake-*,\ " HeaderFilterRegex: 'Source/cm[^/]*\.(h|hxx|cxx)$' CheckOptions: diff --git a/.gitlab/ci/configure_fedora36_tidy.cmake b/.gitlab/ci/configure_fedora36_tidy.cmake index 38414d3b5f..2d0eeeb342 100644 --- a/.gitlab/ci/configure_fedora36_tidy.cmake +++ b/.gitlab/ci/configure_fedora36_tidy.cmake @@ -1,3 +1,5 @@ set(CMake_RUN_CLANG_TIDY ON CACHE BOOL "") +set(CMake_USE_CLANG_TIDY_MODULE ON CACHE BOOL "") +set(CMake_CLANG_TIDY_MODULE "$ENV{CI_PROJECT_DIR}/Utilities/ClangTidyModule/build/libcmake-clang-tidy-module.so" CACHE FILEPATH "") include("${CMAKE_CURRENT_LIST_DIR}/configure_fedora36_common.cmake") diff --git a/.gitlab/ci/env_fedora36_tidy.sh b/.gitlab/ci/env_fedora36_tidy.sh new file mode 100644 index 0000000000..f9f08a3904 --- /dev/null +++ b/.gitlab/ci/env_fedora36_tidy.sh @@ -0,0 +1,7 @@ +cmake \ + -S Utilities/ClangTidyModule \ + -B Utilities/ClangTidyModule/build \ + -DCMAKE_BUILD_TYPE=Release \ + -DRUN_TESTS=ON +cmake --build Utilities/ClangTidyModule/build +ctest --test-dir Utilities/ClangTidyModule/build --output-on-failure diff --git a/CMakeLists.txt b/CMakeLists.txt index 2b9eb2d569..73c2c2e121 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,14 +1,10 @@ # Distributed under the OSI-approved BSD 3-Clause License. See accompanying # file Copyright.txt or https://cmake.org/licensing for details. -cmake_minimum_required(VERSION 3.13...3.23 FATAL_ERROR) +cmake_minimum_required(VERSION 3.13...3.24 FATAL_ERROR) set(CMAKE_USER_MAKE_RULES_OVERRIDE_C ${CMAKE_CURRENT_SOURCE_DIR}/Source/Modules/OverrideC.cmake) set(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX ${CMAKE_CURRENT_SOURCE_DIR}/Source/Modules/OverrideCXX.cmake) -if(POLICY CMP0129) - cmake_policy(SET CMP0129 NEW) # CMake 3.23 -endif() - project(CMake) unset(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX) unset(CMAKE_USER_MAKE_RULES_OVERRIDE_C) @@ -277,6 +273,16 @@ if(CMake_RUN_CLANG_TIDY) endif() set(CMAKE_CXX_CLANG_TIDY "${CLANG_TIDY_COMMAND}") + option(CMake_USE_CLANG_TIDY_MODULE "Use CMake's clang-tidy module." OFF) + if(CMake_USE_CLANG_TIDY_MODULE) + find_library(CMake_CLANG_TIDY_MODULE NAMES cmake-clang-tidy-module DOC "Location of the clang-tidy module") + if(NOT CMake_CLANG_TIDY_MODULE) + message(FATAL_ERROR "CMake_USE_CLANG_TIDY_MODULE is ON but cmake-clang-tidy-module is not found!") + endif() + list(APPEND CMAKE_CXX_CLANG_TIDY "--load=${CMake_CLANG_TIDY_MODULE}") + set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${CMake_CLANG_TIDY_MODULE}") + endif() + # Create a preprocessor definition that depends on .clang-tidy content so # the compile command will change when .clang-tidy changes. This ensures # that a subsequent build re-runs clang-tidy on all sources even if they @@ -286,6 +292,11 @@ if(CMake_RUN_CLANG_TIDY) file(SHA1 ${CMAKE_CURRENT_SOURCE_DIR}/.clang-tidy clang_tidy_sha1) set(CLANG_TIDY_DEFINITIONS "CLANG_TIDY_SHA1=${clang_tidy_sha1}") unset(clang_tidy_sha1) + if(CMake_USE_CLANG_TIDY_MODULE) + file(SHA1 "${CMake_CLANG_TIDY_MODULE}" clang_tidy_module_sha1) + list(APPEND CLANG_TIDY_DEFINITIONS "CLANG_TIDY_MODULE_SHA1=${clang_tidy_module_sha1}") + unset(clang_tidy_module_sha1) + endif() endif() configure_file(.clang-tidy .clang-tidy COPYONLY) diff --git a/Help/command/string.rst b/Help/command/string.rst index 86cbd2ece2..217157cd64 100644 --- a/Help/command/string.rst +++ b/Help/command/string.rst @@ -522,6 +522,17 @@ specifiers: ``%Y`` The current year. +``%z`` + .. versionadded:: 3.26 + + The offset of the time zone from UTC, in hours and minutes, + with format ``+hhmm`` or ``-hhmm``. + +``%Z`` + .. versionadded:: 3.26 + + The time zone name. + Unknown format specifiers will be ignored and copied to the output as-is. diff --git a/Help/guide/tutorial/Adding Support for a Testing Dashboard.rst b/Help/guide/tutorial/Adding Support for a Testing Dashboard.rst index 45d5976981..787e777dc4 100644 --- a/Help/guide/tutorial/Adding Support for a Testing Dashboard.rst +++ b/Help/guide/tutorial/Adding Support for a Testing Dashboard.rst @@ -4,33 +4,40 @@ Step 6: Adding Support for a Testing Dashboard Adding support for submitting our test results to a dashboard is simple. We already defined a number of tests for our project in :ref:`Testing Support <Tutorial Testing Support>`. Now we just have to run -those tests and submit them to a dashboard. To include support for dashboards -we include the :module:`CTest` module in our top-level ``CMakeLists.txt``. +those tests and submit them to CDash. -Replace: -.. literalinclude:: Step6/CMakeLists.txt - :caption: CMakeLists.txt - :name: CMakeLists.txt-enable_testing-remove - :language: cmake - :start-after: # enable testing - :end-before: # does the application run +Exercise 1 - Send Results to a Testing Dashboard +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -With: +Goal +---- -.. literalinclude:: Step7/CMakeLists.txt - :caption: CMakeLists.txt - :name: CMakeLists.txt-include-CTest - :language: cmake - :start-after: # enable testing - :end-before: # does the application run +Display our CTest results with CDash. + +Helpful Resources +----------------- + +* :manual:`ctest(1)` +* :command:`include` +* :module:`CTest` + +Files to Edit +------------- -The :module:`CTest` module will automatically call ``enable_testing()``, so we -can remove it from our CMake files. +* ``CMakeLists.txt`` + +Getting Started +--------------- + +For this exercise, complete ``TODO 1`` in the top-level ``CMakeLists.txt`` by +including the :module:`CTest` module. This will enable testing with CTest as +well as dashboard submissions to CDash, so we can safely remove the call to +:command:`enable_testing`. We will also need to acquire a ``CTestConfig.cmake`` file to be placed in the -top-level directory where we can specify information to CTest about the -project. It contains: +top-level directory. When run, the :manual:`ctest <ctest(1)>` executable will +read this file to gather information about the testing dashboard. It contains: * The project name @@ -41,9 +48,10 @@ project. It contains: * The URL of the CDash instance where the submission's generated documents will be sent -One has been provided for you in this directory. It would normally be -downloaded from the ``Settings`` page of the project on the CDash -instance that will host and display the test results. Once downloaded from +For this tutorial, a public dashboard server is used and its corresponding +``CTestConfig.cmake`` file is provided for you in this step's root directory. +In practice, this file would be downloaded from a project's ``Settings`` page +on the CDash instance intended to host the test results. Once downloaded from CDash, the file should not be modified locally. .. literalinclude:: Step7/CTestConfig.cmake @@ -51,11 +59,16 @@ CDash, the file should not be modified locally. :name: CTestConfig.cmake :language: cmake -The :manual:`ctest <ctest(1)>` executable will read in this file when it runs. -To create a simple dashboard you can run the :manual:`cmake <cmake(1)>` -executable or the :manual:`cmake-gui <cmake-gui(1)>` to configure the project, -but do not build it yet. Instead, change directory to the binary tree, and then -run: + +Build and Run +------------- + +Note that as part of the CDash submission some information about your +development system (e.g. site name or full pathnames) may displayed publicly. + +To create a simple test dashboard, run the :manual:`cmake <cmake(1)>` +executable or the :manual:`cmake-gui <cmake-gui(1)>` to configure the project +but do not build it yet. Instead, navigate to the build directory and run: .. code-block:: console @@ -70,6 +83,28 @@ type must be specified: Or, from an IDE, build the ``Experimental`` target. -The :manual:`ctest <ctest(1)>` executable will build and test the project and -submit the results to Kitware's public dashboard: +The :manual:`ctest <ctest(1)>` executable will build the project, run any +tests, and submit the results to Kitware's public dashboard: https://my.cdash.org/index.php?project=CMakeTutorial. + +Solution +-------- + +The only CMake code changed needed in this step was to enable dashboard +submissions to CDash by including the :module:`CTest` module in our top-level +``CMakeLists.txt``: + +.. raw:: html + + <details><summary>TODO 1: Click to show/hide answer</summary> + +.. literalinclude:: Step7/CMakeLists.txt + :caption: TODO 1: CMakeLists.txt + :name: CMakeLists.txt-include-CTest + :language: cmake + :start-after: # enable testing + :end-before: # does the application run + +.. raw:: html + + </details> diff --git a/Help/guide/tutorial/Adding System Introspection.rst b/Help/guide/tutorial/Adding System Introspection.rst index ba91df47ea..b69abd2920 100644 --- a/Help/guide/tutorial/Adding System Introspection.rst +++ b/Help/guide/tutorial/Adding System Introspection.rst @@ -7,53 +7,156 @@ depends on whether or not the target platform has the ``log`` and ``exp`` functions. Of course almost every platform has these functions but for this tutorial assume that they are not common. -If the platform has ``log`` and ``exp`` then we will use them to compute the -square root in the ``mysqrt`` function. We first test for the availability of -these functions using the :module:`CheckCXXSourceCompiles` module in +Exercise 1 - Assessing Dependency Availability +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Goal +---- + +Change implementation based on available system dependencies. + +Helpful Resources +----------------- + +* :module:`CheckCXXSourceCompiles` +* :command:`target_compile_definitions` + +Files to Edit +------------- + +* ``MathFunctions/CMakeLists.txt`` +* ``MathFunctions/mysqrt.cxx`` + +Getting Started +--------------- + +The starting source code is provided in the ``Step7`` directory. In this +exercise, complete ``TODO 1`` through ``TODO 5``. + +Start by editing ``MathFunctions/CMakeLists.txt``. Include the +:module:`CheckCXXSourceCompiles` module. Then, use +``check_cxx_source_compiles`` to determine whether ``log`` and ``exp`` are +available from ``cmath``. If they are available, use +:command:`target_compile_definitions` to specify ``HAVE_LOG`` and ``HAVE_EXP`` +as compile definitions. + +In the ``MathFunctions/mysqrt.cxx``, include ``cmath``. Then, if the system has +``log`` and ``exp``, use them to compute the square root. + +Build and Run +------------- + +Make a new directory called ``Step7_build``. Run the +:manual:`cmake <cmake(1)>` executable or the +:manual:`cmake-gui <cmake-gui(1)>` to configure the project and then build it +with your chosen build tool and run the ``Tutorial`` executable. + +This can look like the following: + +.. code-block:: console + + mkdir Step7_build + cd Step7_build + cmake ../Step7 + cmake --build . + +Which function gives better results now, ``sqrt`` or ``mysqrt``? + +Solution +-------- + +In this exercise we will use functions from the +:module:`CheckCXXSourceCompiles` module so first we must include it in ``MathFunctions/CMakeLists.txt``. -Add the checks for ``log`` and ``exp`` to ``MathFunctions/CMakeLists.txt``, -after the call to :command:`target_include_directories`: +.. raw:: html + + <details><summary>TODO 1: Click to show/hide answer</summary> .. literalinclude:: Step8/MathFunctions/CMakeLists.txt - :caption: MathFunctions/CMakeLists.txt + :caption: TODO 1: MathFunctions/CMakeLists.txt + :name: MathFunctions/CMakeLists.txt-include-check_cxx_source_compiles + :language: cmake + :start-after: # does this system provide the log and exp functions? + :end-before: check_cxx_source_compiles + +.. raw:: html + + </details> + +Then test for the availability of +``log`` and ``exp`` using ``check_cxx_compiles_source``. This function +lets us try compiling simple code with the required dependency prior to +the true source code compilation. The resulting variables ``HAVE_LOG`` +and ``HAVE_EXP`` represent whether those dependencies are available. + +.. raw:: html + + <details><summary>TODO 2: Click to show/hide answer</summary> + +.. literalinclude:: Step8/MathFunctions/CMakeLists.txt + :caption: TODO 2: MathFunctions/CMakeLists.txt :name: MathFunctions/CMakeLists.txt-check_cxx_source_compiles :language: cmake - :start-after: # to find MathFunctions.h, while we don't. + :start-after: include(CheckCXXSourceCompiles) :end-before: # add compile definitions -If available, use :command:`target_compile_definitions` to specify +.. raw:: html + + </details> + +Next, we need to pass these CMake variables to our source code. This way, +our source code can tell what resources are available. If both ``log`` and +``exp`` are available, use :command:`target_compile_definitions` to specify ``HAVE_LOG`` and ``HAVE_EXP`` as ``PRIVATE`` compile definitions. +.. raw:: html + + <details><summary>TODO 3: Click to show/hide answer</summary> + .. literalinclude:: Step8/MathFunctions/CMakeLists.txt - :caption: MathFunctions/CMakeLists.txt + :caption: TODO 3: MathFunctions/CMakeLists.txt :name: MathFunctions/CMakeLists.txt-target_compile_definitions :language: cmake :start-after: # add compile definitions :end-before: # install libs -If ``log`` and ``exp`` are available on the system, then we will use them to -compute the square root in the ``mysqrt`` function. Add the following code to -the ``mysqrt`` function in ``MathFunctions/mysqrt.cxx`` (don't forget the -``#endif`` before returning the result!): +.. raw:: html -.. literalinclude:: Step8/MathFunctions/mysqrt.cxx - :caption: MathFunctions/mysqrt.cxx - :name: MathFunctions/mysqrt.cxx-ifdef - :language: c++ - :start-after: // if we have both log and exp then use them - :end-before: // do ten iterations + </details> + +Since we may be using ``log`` and ``exp``, we need to modify +``mysqrt.cxx`` to include ``cmath``. + +.. raw:: html -We will also need to modify ``mysqrt.cxx`` to include ``cmath``. + <details><summary>TODO 4: Click to show/hide answer</summary> .. literalinclude:: Step8/MathFunctions/mysqrt.cxx - :caption: MathFunctions/mysqrt.cxx + :caption: TODO 4: MathFunctions/mysqrt.cxx :name: MathFunctions/mysqrt.cxx-include-cmath :language: c++ :end-before: #include <iostream> -Run the :manual:`cmake <cmake(1)>` executable or the -:manual:`cmake-gui <cmake-gui(1)>` to configure the project and then build it -with your chosen build tool and run the Tutorial executable. +.. raw:: html -Which function gives better results now, ``sqrt`` or ``mysqrt``? + </details> + +If ``log`` and ``exp`` are available on the system, then use them to +compute the square root in the ``mysqrt`` function. The ``mysqrt`` function in +``MathFunctions/mysqrt.cxx`` will look as follows: + +.. raw:: html + + <details><summary>TODO 5: Click to show/hide answer</summary> + +.. literalinclude:: Step8/MathFunctions/mysqrt.cxx + :caption: TODO 5: MathFunctions/mysqrt.cxx + :name: MathFunctions/mysqrt.cxx-ifdef + :language: c++ + :start-after: // if we have both log and exp then use them + :end-before: // do ten iterations + +.. raw:: html + + </details> diff --git a/Help/guide/tutorial/Installing and Testing.rst b/Help/guide/tutorial/Installing and Testing.rst index fa13040aec..c0202643b1 100644 --- a/Help/guide/tutorial/Installing and Testing.rst +++ b/Help/guide/tutorial/Installing and Testing.rst @@ -145,7 +145,7 @@ are similar. To the end of the top-level ``CMakeLists.txt`` we add: :name: TODO 3,4: CMakeLists.txt-install-TARGETS :language: cmake :start-after: # add the install targets - :end-before: # enable testing + :end-before: # TODO 1: Replace enable_testing() with include(CTest) .. raw:: html diff --git a/Help/guide/tutorial/Step6/CMakeLists.txt b/Help/guide/tutorial/Step6/CMakeLists.txt index da9e8521e3..c11e307736 100644 --- a/Help/guide/tutorial/Step6/CMakeLists.txt +++ b/Help/guide/tutorial/Step6/CMakeLists.txt @@ -45,6 +45,7 @@ install(FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h" DESTINATION include ) +# TODO 1: Replace enable_testing() with include(CTest) # enable testing enable_testing() diff --git a/Help/guide/tutorial/Step7/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step7/MathFunctions/CMakeLists.txt index b4724c4a10..e5bdc4da15 100644 --- a/Help/guide/tutorial/Step7/MathFunctions/CMakeLists.txt +++ b/Help/guide/tutorial/Step7/MathFunctions/CMakeLists.txt @@ -9,6 +9,26 @@ target_include_directories(MathFunctions # link our compiler flags interface library target_link_libraries(MathFunctions tutorial_compiler_flags) +# TODO 1: Include CheckCXXSourceCompiles + +# TODO 2: Use check_cxx_source_compiles with simple C++ code to verify +# availability of: +# * std::log +# * std::exp +# Store the results in HAVE_LOG and HAVE_EXP respectively. + +# Hint: Sample C++ code which uses log: +# #include <cmath> +# int main() { +# std::log(1.0); +# return 0; +# } + +# TODO 3: Conditionally on HAVE_LOG and HAVE_EXP, add private compile +# definitions "HAVE_LOG" and "HAVE_EXP" to the MathFunctions target. + +#Hint: Use target_compile_definitions() + # install libs set(installable_libs MathFunctions tutorial_compiler_flags) install(TARGETS ${installable_libs} DESTINATION lib) diff --git a/Help/guide/tutorial/Step7/MathFunctions/mysqrt.cxx b/Help/guide/tutorial/Step7/MathFunctions/mysqrt.cxx index abe767d5ae..3d2492a648 100644 --- a/Help/guide/tutorial/Step7/MathFunctions/mysqrt.cxx +++ b/Help/guide/tutorial/Step7/MathFunctions/mysqrt.cxx @@ -1,5 +1,6 @@ #include <iostream> +// TODO 4: include cmath #include "MathFunctions.h" // a hack square root calculation using simple operations @@ -9,6 +10,14 @@ double mysqrt(double x) return 0; } + // TODO 5: If both HAVE_LOG and HAVE_EXP are defined, use the following: + //// double result = std::exp(std::log(x) * 0.5); + //// std::cout << "Computing sqrt of " << x << " to be " << result + //// << " using log and exp" << std::endl; + // else, use the existing logic. + + // Hint: Don't forget the #endif before returning the result! + double result = x; // do ten iterations @@ -20,5 +29,6 @@ double mysqrt(double x) result = result + 0.5 * delta / result; std::cout << "Computing sqrt of " << x << " to be " << result << std::endl; } + return result; } diff --git a/Help/prop_tgt/COMMON_LANGUAGE_RUNTIME.rst b/Help/prop_tgt/COMMON_LANGUAGE_RUNTIME.rst index adfa6f77a1..7ce0023c81 100644 --- a/Help/prop_tgt/COMMON_LANGUAGE_RUNTIME.rst +++ b/Help/prop_tgt/COMMON_LANGUAGE_RUNTIME.rst @@ -7,13 +7,30 @@ By setting this target property, the target is configured to build with ``C++/CLI`` support. The Visual Studio generator defines the ``clr`` parameter depending on -the value of ``COMMON_LANGUAGE_RUNTIME``: +the value of the ``COMMON_LANGUAGE_RUNTIME`` target property: -* property not set: native C++ (i.e. default) -* property set but empty: mixed unmanaged/managed C++ -* property set to any non empty value: managed C++ +Not Set (default) -Supported values: ``""``, ``"pure"``, ``"safe"`` + Native C++. + +``""`` (set but empty) + + Mixed unmanaged/managed C++ using .NET Framework. + +``netcore`` + .. versionadded:: 3.26 + + Mixed unmanaged/managed C++ using .NET Core. + + This required VS 2019's v142 toolset or higher. + +``pure`` + + Managed C++. + +``safe`` + + Managed C++. This property is only evaluated :ref:`Visual Studio Generators` for VS 2010 and above. diff --git a/Help/release/dev/0-sample-topic.rst b/Help/release/dev/0-sample-topic.rst new file mode 100644 index 0000000000..e4cc01e23f --- /dev/null +++ b/Help/release/dev/0-sample-topic.rst @@ -0,0 +1,7 @@ +0-sample-topic +-------------- + +* This is a sample release note for the change in a topic. + Developers should add similar notes for each topic branch + making a noteworthy change. Each document should be named + and titled to match the topic name to avoid merge conflicts. diff --git a/Help/release/dev/UseSWIG-perl5.rst b/Help/release/dev/UseSWIG-perl5.rst new file mode 100644 index 0000000000..67d416133e --- /dev/null +++ b/Help/release/dev/UseSWIG-perl5.rst @@ -0,0 +1,4 @@ +UseSWIG-perl5 +------------- + +* The :module:`UseSWIG` module gained the support of ``perl5`` language. diff --git a/Help/release/dev/timestamp-timezone.rst b/Help/release/dev/timestamp-timezone.rst new file mode 100644 index 0000000000..178fa9ae05 --- /dev/null +++ b/Help/release/dev/timestamp-timezone.rst @@ -0,0 +1,5 @@ +timestamp-timezone +------------------ + +* The :command:`string(TIMESTAMP)` and :command:`file(TIMESTAMP)` commands + now support the ``%z`` and ``%Z`` specifiers for the time zone. diff --git a/Help/release/dev/trace-try_compile.rst b/Help/release/dev/trace-try_compile.rst new file mode 100644 index 0000000000..886aaad272 --- /dev/null +++ b/Help/release/dev/trace-try_compile.rst @@ -0,0 +1,5 @@ +trace-try_compile +----------------- + +* The :option:`cmake --trace` option now follows :command:`try_compile` and + :command:`try_run` invocations. diff --git a/Help/release/index.rst b/Help/release/index.rst index b6ecf7b097..50e06bb369 100644 --- a/Help/release/index.rst +++ b/Help/release/index.rst @@ -7,6 +7,8 @@ CMake Release Notes This file should include the adjacent "dev.txt" file in development versions but not in release versions. +.. include:: dev.txt + Releases ======== diff --git a/Modules/CMakeSwiftInformation.cmake b/Modules/CMakeSwiftInformation.cmake index 16726d2d27..62f7ef2a41 100644 --- a/Modules/CMakeSwiftInformation.cmake +++ b/Modules/CMakeSwiftInformation.cmake @@ -65,10 +65,22 @@ set(CMAKE_Swift_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL -libc MD) set(CMAKE_Swift_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug -libc MTd) set(CMAKE_Swift_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebugDLL -libc MDd) -set(CMAKE_Swift_FLAGS_DEBUG_INIT "-Onone -g") -set(CMAKE_Swift_FLAGS_RELEASE_INIT "-O") -set(CMAKE_Swift_FLAGS_RELWITHDEBINFO_INIT "-O -g") -set(CMAKE_Swift_FLAGS_MINSIZEREL_INIT "-Osize") +if(CMAKE_GENERATOR STREQUAL "Xcode") + # Xcode has a separate Xcode project option (SWIFT_COMPILATION_MODE) used to set + # whether compiling with whole-module optimizations or incrementally. Setting + # these options here will have no effect when compiling with the built-in driver, + # and will explode violently, leaving build products in the source directory, when + # using the old swift driver. + set(CMAKE_Swift_FLAGS_DEBUG_INIT "-Onone -g") + set(CMAKE_Swift_FLAGS_RELEASE_INIT "-O") + set(CMAKE_Swift_FLAGS_RELWITHDEBINFO_INIT "-O -g") + set(CMAKE_Swift_FLAGS_MINSIZEREL_INIT "-Osize") +else() + set(CMAKE_Swift_FLAGS_DEBUG_INIT "-Onone -g -incremental") + set(CMAKE_Swift_FLAGS_RELEASE_INIT "-O -wmo") + set(CMAKE_Swift_FLAGS_RELWITHDEBINFO_INIT "-O -g -wmo") + set(CMAKE_Swift_FLAGS_MINSIZEREL_INIT "-Osize -wmo") +endif() if(CMAKE_EXECUTABLE_FORMAT STREQUAL "ELF") if(NOT DEFINED CMAKE_Swift_LINK_WHAT_YOU_USE_FLAG) @@ -91,7 +103,7 @@ if(NOT CMAKE_Swift_NUM_THREADS MATCHES "^[0-9]+$") endif() if(NOT CMAKE_Swift_CREATE_SHARED_LIBRARY) - set(CMAKE_Swift_CREATE_SHARED_LIBRARY "<CMAKE_Swift_COMPILER> -output-file-map <SWIFT_OUTPUT_FILE_MAP> -incremental -j ${CMAKE_Swift_NUM_THREADS} -emit-library -o <TARGET> -module-name <SWIFT_MODULE_NAME> -module-link-name <SWIFT_LIBRARY_NAME> -emit-module -emit-module-path <SWIFT_MODULE> -emit-dependencies <DEFINES> <FLAGS> <INCLUDES> <SWIFT_SOURCES> <LINK_FLAGS> <SONAME_FLAG> <TARGET_INSTALLNAME_DIR><TARGET_SONAME> ${CMAKE_Swift_IMPLIB_LINKER_FLAGS} <LINK_LIBRARIES>") + set(CMAKE_Swift_CREATE_SHARED_LIBRARY "<CMAKE_Swift_COMPILER> -j ${CMAKE_Swift_NUM_THREADS} -num-threads ${CMAKE_Swift_NUM_THREADS} -emit-library -o <TARGET> -module-name <SWIFT_MODULE_NAME> -module-link-name <SWIFT_LIBRARY_NAME> -emit-module -emit-module-path <SWIFT_MODULE> -emit-dependencies <DEFINES> <FLAGS> <INCLUDES> <SWIFT_SOURCES> <LINK_FLAGS> <SONAME_FLAG> <TARGET_INSTALLNAME_DIR><TARGET_SONAME> ${CMAKE_Swift_IMPLIB_LINKER_FLAGS} <LINK_LIBRARIES>") endif() if(NOT CMAKE_Swift_CREATE_SHARED_MODULE) @@ -99,11 +111,11 @@ if(NOT CMAKE_Swift_CREATE_SHARED_MODULE) endif() if(NOT CMAKE_Swift_LINK_EXECUTABLE) - set(CMAKE_Swift_LINK_EXECUTABLE "<CMAKE_Swift_COMPILER> -output-file-map <SWIFT_OUTPUT_FILE_MAP> -incremental -j ${CMAKE_Swift_NUM_THREADS} -emit-executable -o <TARGET> -emit-dependencies <DEFINES> <FLAGS> <INCLUDES> <SWIFT_SOURCES> <LINK_FLAGS> <LINK_LIBRARIES>") + set(CMAKE_Swift_LINK_EXECUTABLE "<CMAKE_Swift_COMPILER> -j ${CMAKE_Swift_NUM_THREADS} -num-threads ${CMAKE_Swift_NUM_THREADS} -emit-executable -o <TARGET> -emit-dependencies <DEFINES> <FLAGS> <INCLUDES> <SWIFT_SOURCES> <LINK_FLAGS> <LINK_LIBRARIES>") endif() if(NOT CMAKE_Swift_CREATE_STATIC_LIBRARY) - set(CMAKE_Swift_CREATE_STATIC_LIBRARY "<CMAKE_Swift_COMPILER> -output-file-map <SWIFT_OUTPUT_FILE_MAP> -incremental -j ${CMAKE_Swift_NUM_THREADS} -emit-library -static -o <TARGET> -module-name <SWIFT_MODULE_NAME> -module-link-name <SWIFT_LIBRARY_NAME> -emit-module -emit-module-path <SWIFT_MODULE> -emit-dependencies <DEFINES> <FLAGS> <INCLUDES> <SWIFT_SOURCES> <LINK_FLAGS> <LINK_LIBRARIES>") + set(CMAKE_Swift_CREATE_STATIC_LIBRARY "<CMAKE_Swift_COMPILER> -j ${CMAKE_Swift_NUM_THREADS} -num-threads ${CMAKE_Swift_NUM_THREADS} -emit-library -static -o <TARGET> -module-name <SWIFT_MODULE_NAME> -module-link-name <SWIFT_LIBRARY_NAME> -emit-module -emit-module-path <SWIFT_MODULE> -emit-dependencies <DEFINES> <FLAGS> <INCLUDES> <SWIFT_SOURCES> <LINK_FLAGS> <LINK_LIBRARIES>") set(CMAKE_Swift_ARCHIVE_CREATE "<CMAKE_AR> crs <TARGET> <OBJECTS>") set(CMAKE_Swift_ARCHIVE_FINISH "") diff --git a/Modules/ExternalProject.cmake b/Modules/ExternalProject.cmake index 22a25bd1f5..141b18586f 100644 --- a/Modules/ExternalProject.cmake +++ b/Modules/ExternalProject.cmake @@ -3642,7 +3642,7 @@ function(_ep_extract_configure_command var name) ) endif() - list(APPEND cmd "<SOURCE_DIR><SOURCE_SUBDIR>") + list(APPEND cmd -S "<SOURCE_DIR><SOURCE_SUBDIR>" -B "<BINARY_DIR>") endif() set("${var}" "${cmd}" PARENT_SCOPE) diff --git a/Modules/FindZLIB.cmake b/Modules/FindZLIB.cmake index be5c775b20..cfe67158f1 100644 --- a/Modules/FindZLIB.cmake +++ b/Modules/FindZLIB.cmake @@ -60,6 +60,14 @@ module where to look. #]=======================================================================] +if(ZLIB_FIND_COMPONENTS AND NOT ZLIB_FIND_QUIETLY) + message(AUTHOR_WARNING + "ZLIB does not provide any COMPONENTS. Calling\n" + " find_package(ZLIB COMPONENTS ...)\n" + "will always fail." + ) +endif() + set(_ZLIB_SEARCHES) # Search ZLIB_ROOT first if it is set. @@ -164,7 +172,8 @@ endif() include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) FIND_PACKAGE_HANDLE_STANDARD_ARGS(ZLIB REQUIRED_VARS ZLIB_LIBRARY ZLIB_INCLUDE_DIR - VERSION_VAR ZLIB_VERSION_STRING) + VERSION_VAR ZLIB_VERSION_STRING + HANDLE_COMPONENTS) if(ZLIB_FOUND) set(ZLIB_INCLUDE_DIRS ${ZLIB_INCLUDE_DIR}) diff --git a/Modules/Internal/CheckSourceCompiles.cmake b/Modules/Internal/CheckSourceCompiles.cmake index eadf3da504..bf5a82d8bc 100644 --- a/Modules/Internal/CheckSourceCompiles.cmake +++ b/Modules/Internal/CheckSourceCompiles.cmake @@ -9,7 +9,7 @@ cmake_policy(SET CMP0057 NEW) # if() supports IN_LIST function(CMAKE_CHECK_SOURCE_COMPILES _lang _source _var) if(NOT DEFINED "${_var}") - + set(_lang_filename "src") if(_lang STREQUAL "C") set(_lang_textual "C") set(_lang_ext "c") @@ -34,6 +34,13 @@ function(CMAKE_CHECK_SOURCE_COMPILES _lang _source _var) elseif(_lang STREQUAL "OBJCXX") set(_lang_textual "Objective-C++") set(_lang_ext "mm") + elseif(_lang STREQUAL "Swift") + set(_lang_textual "Swift") + set(_lang_ext "swift") + if (NOT DEFINED CMAKE_TRY_COMPILE_TARGET_TYPE + OR CMAKE_TRY_COMPILE_TARGET_TYPE STREQUAL "EXECUTABLE") + set(_lang_filename "main") + endif() else() message (SEND_ERROR "check_source_compiles: ${_lang}: unknown language.") return() @@ -92,7 +99,7 @@ function(CMAKE_CHECK_SOURCE_COMPILES _lang _source _var) endif() string(APPEND _source "\n") try_compile(${_var} - SOURCE_FROM_VAR "src.${_SRC_EXT}" _source + SOURCE_FROM_VAR "${_lang_filename}.${_SRC_EXT}" _source COMPILE_DEFINITIONS -D${_var} ${CMAKE_REQUIRED_DEFINITIONS} ${CHECK_${LANG}_SOURCE_COMPILES_ADD_LINK_OPTIONS} ${CHECK_${LANG}_SOURCE_COMPILES_ADD_LIBRARIES} diff --git a/Modules/UseSWIG.cmake b/Modules/UseSWIG.cmake index fd6596b854..e0e01f57e0 100644 --- a/Modules/UseSWIG.cmake +++ b/Modules/UseSWIG.cmake @@ -378,6 +378,7 @@ set(SWIG_PYTHON_EXTRA_FILE_EXTENSIONS ".py") set(SWIG_JAVA_EXTRA_FILE_EXTENSIONS ".java" "JNI.java") set(SWIG_CSHARP_EXTRA_FILE_EXTENSIONS ".cs" "PINVOKE.cs") set(SWIG_PERL_EXTRA_FILE_EXTENSIONS ".pm") +set(SWIG_PERL5_EXTRA_FILE_EXTENSIONS ".pm") set(SWIG_MANAGE_SUPPORT_FILES_SCRIPT "${CMAKE_CURRENT_LIST_DIR}/UseSWIG/ManageSupportFiles.cmake") @@ -414,8 +415,8 @@ macro(SWIG_MODULE_INITIALIZE name language) endif() if(SWIG_MODULE_${name}_LANGUAGE STREQUAL "UNKNOWN") message(FATAL_ERROR "SWIG Error: Language \"${language}\" not found") - elseif(SWIG_MODULE_${name}_LANGUAGE STREQUAL "PERL" AND - NOT "-shadow" IN_LIST SWIG_MODULE_${name}_EXTRA_FLAGS) + elseif((SWIG_MODULE_${name}_LANGUAGE STREQUAL "PERL" OR SWIG_MODULE_${name}_LANGUAGE STREQUAL "PERL5") + AND NOT "-shadow" IN_LIST SWIG_MODULE_${name}_EXTRA_FLAGS) list(APPEND SWIG_MODULE_${name}_EXTRA_FLAGS "-shadow") endif() endmacro() @@ -971,7 +972,7 @@ function(SWIG_ADD_LIBRARY name) if (APPLE) set_target_properties (${target_name} PROPERTIES SUFFIX ".bundle") endif () - elseif (swig_lowercase_language STREQUAL "perl") + elseif (swig_lowercase_language STREQUAL "perl" OR swig_lowercase_language STREQUAL "perl5") # assume empty prefix because we expect the module to be dynamically loaded set_target_properties (${target_name} PROPERTIES PREFIX "") if (APPLE) diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index c51f4214d3..76955b4777 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,8 +1,8 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 25) -set(CMake_VERSION_PATCH 0) -set(CMake_VERSION_RC 2) +set(CMake_VERSION_PATCH 20221101) +#set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) # Start with the full version number used in tags. It has no dev info. diff --git a/Source/CursesDialog/ccmake.cxx b/Source/CursesDialog/ccmake.cxx index 1f7776c148..70ed648b56 100644 --- a/Source/CursesDialog/ccmake.cxx +++ b/Source/CursesDialog/ccmake.cxx @@ -77,7 +77,7 @@ int main(int argc, char const* const* argv) cmDocumentation doc; doc.addCMakeStandardDocSections(); if (doc.CheckOptions(argc, argv)) { - cmake hcm(cmake::RoleInternal, cmState::Unknown); + cmake hcm(cmake::RoleInternal, cmState::Help); hcm.SetHomeDirectory(""); hcm.SetHomeOutputDirectory(""); hcm.AddCMakePaths(); diff --git a/Source/QtDialog/CMakeSetup.cxx b/Source/QtDialog/CMakeSetup.cxx index fb12b7d9f4..591b793357 100644 --- a/Source/QtDialog/CMakeSetup.cxx +++ b/Source/QtDialog/CMakeSetup.cxx @@ -79,7 +79,7 @@ int main(int argc, char** argv) doc.addCMakeStandardDocSections(); if (argc2 > 1 && doc.CheckOptions(argc2, argv2)) { // Construct and print requested documentation. - cmake hcm(cmake::RoleInternal, cmState::Unknown); + cmake hcm(cmake::RoleInternal, cmState::Help); hcm.SetHomeDirectory(""); hcm.SetHomeOutputDirectory(""); hcm.AddCMakePaths(); diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index 50bc78ca58..2c61163abe 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -939,13 +939,13 @@ void cmExportFileGenerator::GeneratePolicyHeaderCode(std::ostream& os) // Isolate the file policy level. // Support CMake versions as far back as 2.6 but also support using NEW - // policy settings for up to CMake 3.23 (this upper limit may be reviewed + // policy settings for up to CMake 3.24 (this upper limit may be reviewed // and increased from time to time). This reduces the opportunity for CMake // warnings when an older export file is later used with newer CMake // versions. /* clang-format off */ os << "cmake_policy(PUSH)\n" - << "cmake_policy(VERSION 2.8.3...3.23)\n"; + << "cmake_policy(VERSION 2.8.3...3.24)\n"; /* clang-format on */ } diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx index 3f8378b027..60b0a7b2ed 100644 --- a/Source/cmFindPackageCommand.cxx +++ b/Source/cmFindPackageCommand.cxx @@ -377,6 +377,8 @@ private: # pragma diag_suppress 1222 // invalid error number (3288, but works anyway) # define CM_LCC_DIAG_SUPPRESS_3288 # pragma diag_suppress 3288 // parameter was declared but never referenced +# define CM_LCC_DIAG_SUPPRESS_3301 +# pragma diag_suppress 3301 // parameter was declared but never referenced #endif void ResetGenerator() @@ -421,6 +423,11 @@ bool TryGeneratedPaths(CallbackFn&& filesCollector, return false; } +#ifdef CM_LCC_DIAG_SUPPRESS_3301 +# undef CM_LCC_DIAG_SUPPRESS_3301 +# pragma diag_default 3301 +#endif + #ifdef CM_LCC_DIAG_SUPPRESS_3288 # undef CM_LCC_DIAG_SUPPRESS_3288 # pragma diag_default 3288 diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 6195d1ff07..8fd7321533 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -5532,7 +5532,7 @@ cmGeneratorTarget::GetTargetSourceFileFlags(const cmSourceFile* sf) const } else if (cmHasLiteralPrefix(*location, "Resources/")) { flags.Type = cmGeneratorTarget::SourceFileTypeDeepResource; if (stripResources) { - flags.MacFolder += strlen("Resources/"); + flags.MacFolder += cmStrLen("Resources/"); } } else { flags.Type = cmGeneratorTarget::SourceFileTypeMacContent; @@ -8515,9 +8515,14 @@ cmGeneratorTarget::ManagedType cmGeneratorTarget::CheckManagedType( // lib // 2. empty propval: add /clr as flag, mixed unmanaged/managed // target, has import lib - // 3. any value (safe,pure): add /clr:[propval] as flag, target with + // 3. netcore propval: add /clr:netcore as flag, mixed + // unmanaged/managed target, has import lib. + // 4. any value (safe,pure): add /clr:[propval] as flag, target with // managed code only, no import lib - return propval.empty() ? ManagedType::Mixed : ManagedType::Managed; + if (propval.empty() || propval == "netcore") { + return ManagedType::Mixed; + } + return ManagedType::Managed; } cmGeneratorTarget::ManagedType cmGeneratorTarget::GetManagedType( diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 67b6e92515..11520b4e27 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -4407,12 +4407,20 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects( buildSettings->AddAttribute("CODE_SIGNING_ALLOWED", this->CreateString("NO")); } + auto debugConfigs = this->GetCMakeInstance()->GetDebugConfigs(); + std::set<std::string> debugConfigSet(debugConfigs.begin(), + debugConfigs.end()); for (auto& config : configs) { CreateGlobalXCConfigSettings(root, config.second, config.first); cmXCodeObject* buildSettingsForCfg = this->CreateFlatClone(buildSettings); + if (debugConfigSet.count(cmSystemTools::UpperCase(config.first)) == 0) { + buildSettingsForCfg->AddAttribute("SWIFT_COMPILATION_MODE", + this->CreateString("wholemodule")); + } + // Put this last so it can override existing settings // Convert "CMAKE_XCODE_ATTRIBUTE_*" variables directly. for (const auto& var : this->CurrentMakefile->GetDefinitions()) { diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 6e0d704f93..2091f27462 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -375,19 +375,15 @@ public: ++this->Makefile->RecursionDepth; this->Makefile->ExecutionStatusStack.push_back(&status); #if !defined(CMAKE_BOOTSTRAP) - if (this->Makefile->GetCMakeInstance()->IsProfilingEnabled()) { - this->Makefile->GetCMakeInstance()->GetProfilingOutput().StartEntry(lff, - lfc); - } + this->ProfilingDataRAII = + this->Makefile->GetCMakeInstance()->CreateProfilingEntry(lff, lfc); #endif } ~cmMakefileCall() { #if !defined(CMAKE_BOOTSTRAP) - if (this->Makefile->GetCMakeInstance()->IsProfilingEnabled()) { - this->Makefile->GetCMakeInstance()->GetProfilingOutput().StopEntry(); - } + this->ProfilingDataRAII.reset(); #endif this->Makefile->ExecutionStatusStack.pop_back(); --this->Makefile->RecursionDepth; @@ -399,6 +395,9 @@ public: private: cmMakefile* Makefile; +#if !defined(CMAKE_BOOTSTRAP) + cm::optional<cmMakefileProfilingData::RAII> ProfilingDataRAII; +#endif }; void cmMakefile::OnExecuteCommand(std::function<void()> callback) @@ -3584,6 +3583,9 @@ int cmMakefile::TryCompile(const std::string& srcdir, gg->RecursionDepth = this->RecursionDepth; cm.SetGlobalGenerator(std::move(gg)); + // copy trace state + cm.SetTraceRedirect(this->GetCMakeInstance()); + // do a configure cm.SetHomeDirectory(srcdir); cm.SetHomeOutputDirectory(bindir); @@ -4470,12 +4472,12 @@ bool cmMakefile::SetPolicy(cmPolicies::PolicyID id, } // Deprecate old policies. - if (status == cmPolicies::OLD && id <= cmPolicies::CMP0102 && + if (status == cmPolicies::OLD && id <= cmPolicies::CMP0108 && !(this->GetCMakeInstance()->GetIsInTryCompile() && ( // Policies set by cmCoreTryCompile::TryCompileCode. id == cmPolicies::CMP0065 || id == cmPolicies::CMP0083 || - id == cmPolicies::CMP0091)) && + id == cmPolicies::CMP0091 || id == cmPolicies::CMP0104)) && (!this->IsSet("CMAKE_WARN_DEPRECATED") || this->IsOn("CMAKE_WARN_DEPRECATED"))) { this->IssueMessage(MessageType::DEPRECATION_WARNING, diff --git a/Source/cmMakefileProfilingData.cxx b/Source/cmMakefileProfilingData.cxx index 1cd97c934e..e4844f3576 100644 --- a/Source/cmMakefileProfilingData.cxx +++ b/Source/cmMakefileProfilingData.cxx @@ -4,8 +4,12 @@ #include <chrono> #include <stdexcept> +#include <type_traits> +#include <utility> #include <vector> +#include <cm/utility> + #include <cm3p/json/value.h> #include <cm3p/json/writer.h> @@ -46,6 +50,23 @@ cmMakefileProfilingData::~cmMakefileProfilingData() noexcept void cmMakefileProfilingData::StartEntry(const cmListFileFunction& lff, cmListFileContext const& lfc) { + cm::optional<Json::Value> argsValue(cm::in_place, Json::objectValue); + if (!lff.Arguments().empty()) { + std::string args; + for (auto const& a : lff.Arguments()) { + args = cmStrCat(args, args.empty() ? "" : " ", a.Value); + } + (*argsValue)["functionArgs"] = args; + } + (*argsValue)["location"] = + cmStrCat(lfc.FilePath, ':', std::to_string(lfc.Line)); + this->StartEntry("script", lff.LowerCaseName(), std::move(argsValue)); +} + +void cmMakefileProfilingData::StartEntry(const std::string& category, + const std::string& name, + cm::optional<Json::Value> args) +{ /* Do not try again if we previously failed to write to output. */ if (!this->ProfileStream.good()) { return; @@ -58,24 +79,17 @@ void cmMakefileProfilingData::StartEntry(const cmListFileFunction& lff, cmsys::SystemInformation info; Json::Value v; v["ph"] = "B"; - v["name"] = lff.LowerCaseName(); - v["cat"] = "cmake"; + v["name"] = name; + v["cat"] = category; v["ts"] = static_cast<Json::Value::UInt64>( std::chrono::duration_cast<std::chrono::microseconds>( std::chrono::steady_clock::now().time_since_epoch()) .count()); v["pid"] = static_cast<int>(info.GetProcessId()); v["tid"] = 0; - Json::Value argsValue; - if (!lff.Arguments().empty()) { - std::string args; - for (auto const& a : lff.Arguments()) { - args += (args.empty() ? "" : " ") + a.Value; - } - argsValue["functionArgs"] = args; + if (args) { + v["args"] = *std::move(args); } - argsValue["location"] = lfc.FilePath + ":" + std::to_string(lfc.Line); - v["args"] = argsValue; this->JsonWriter->write(v, &this->ProfileStream); } catch (std::ios_base::failure& fail) { @@ -112,3 +126,27 @@ void cmMakefileProfilingData::StopEntry() cmSystemTools::Error("Error writing profiling output!"); } } + +cmMakefileProfilingData::RAII::RAII(RAII&& other) noexcept + : Data(other.Data) +{ + other.Data = nullptr; +} + +cmMakefileProfilingData::RAII::~RAII() +{ + if (this->Data) { + this->Data->StopEntry(); + } +} + +cmMakefileProfilingData::RAII& cmMakefileProfilingData::RAII::operator=( + RAII&& other) noexcept +{ + if (this->Data) { + this->Data->StopEntry(); + } + this->Data = other.Data; + other.Data = nullptr; + return *this; +} diff --git a/Source/cmMakefileProfilingData.h b/Source/cmMakefileProfilingData.h index a86764a707..e8d7dfa803 100644 --- a/Source/cmMakefileProfilingData.h +++ b/Source/cmMakefileProfilingData.h @@ -3,6 +3,11 @@ #pragma once #include <memory> #include <string> +#include <utility> + +#include <cm/optional> + +#include <cm3p/json/value.h> // IWYU pragma: keep #include "cmsys/FStream.hxx" @@ -19,8 +24,33 @@ public: cmMakefileProfilingData(const std::string&); ~cmMakefileProfilingData() noexcept; void StartEntry(const cmListFileFunction& lff, cmListFileContext const& lfc); + void StartEntry(const std::string& category, const std::string& name, + cm::optional<Json::Value> args = cm::nullopt); void StopEntry(); + class RAII + { + public: + RAII() = delete; + RAII(const RAII&) = delete; + RAII(RAII&&) noexcept; + + template <typename... Args> + RAII(cmMakefileProfilingData& data, Args&&... args) + : Data(&data) + { + this->Data->StartEntry(std::forward<Args>(args)...); + } + + ~RAII(); + + RAII& operator=(const RAII&) = delete; + RAII& operator=(RAII&&) noexcept; + + private: + cmMakefileProfilingData* Data = nullptr; + }; + private: cmsys::ofstream ProfileStream; std::unique_ptr<Json::StreamWriter> JsonWriter; diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index bda8a5f48d..895a4c3763 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -372,7 +372,6 @@ void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile, vars.SwiftLibraryName = "$SWIFT_LIBRARY_NAME"; vars.SwiftModule = "$SWIFT_MODULE"; vars.SwiftModuleName = "$SWIFT_MODULE_NAME"; - vars.SwiftOutputFileMap = "$SWIFT_OUTPUT_FILE_MAP"; vars.SwiftSources = "$SWIFT_SOURCES"; vars.Defines = "$DEFINES"; @@ -1072,12 +1071,6 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement( cmOutputConverter::SHELL); }(vars["SWIFT_MODULE_NAME"]); - const std::string map = cmStrCat(gt->GetSupportDirectory(), '/', config, - '/', "output-file-map.json"); - vars["SWIFT_OUTPUT_FILE_MAP"] = - this->GetLocalGenerator()->ConvertToOutputFormat( - this->ConvertToNinjaPath(map), cmOutputConverter::SHELL); - vars["SWIFT_SOURCES"] = [this, config]() -> std::string { std::vector<cmSourceFile const*> sources; std::stringstream oss; @@ -1101,6 +1094,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement( vars["DEFINES"] = this->GetDefines("Swift", config); vars["FLAGS"] = this->GetFlags("Swift", config); vars["INCLUDES"] = this->GetIncludes("Swift", config); + this->GenerateSwiftOutputFileMap(config, vars["FLAGS"]); } // Compute specific libraries to link with. diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index e4427f5d74..ae6a51077b 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -1177,30 +1177,42 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements( } this->GetImplFileStream(fileConfig) << "\n"; +} - if (!this->Configs[config].SwiftOutputMap.empty()) { - std::string const mapFilePath = - cmStrCat(this->GeneratorTarget->GetSupportDirectory(), '/', config, '/', - "output-file-map.json"); - std::string const targetSwiftDepsPath = [this, config]() -> std::string { - cmGeneratorTarget const* target = this->GeneratorTarget; - if (cmValue name = target->GetProperty("Swift_DEPENDENCIES_FILE")) { - return *name; - } - return this->ConvertToNinjaPath( - cmStrCat(target->GetSupportDirectory(), '/', config, '/', - target->GetName(), ".swiftdeps")); - }(); +void cmNinjaTargetGenerator::GenerateSwiftOutputFileMap( + const std::string& config, std::string& flags) +{ + if (this->Configs[config].SwiftOutputMap.empty()) { + return; + } - // build the global target dependencies - // https://github.com/apple/swift/blob/master/docs/Driver.md#output-file-maps - Json::Value deps(Json::objectValue); - deps["swift-dependencies"] = targetSwiftDepsPath; - this->Configs[config].SwiftOutputMap[""] = deps; + std::string const targetSwiftDepsPath = [this, config]() -> std::string { + cmGeneratorTarget const* target = this->GeneratorTarget; + if (cmValue name = target->GetProperty("Swift_DEPENDENCIES_FILE")) { + return *name; + } + return this->ConvertToNinjaPath(cmStrCat(target->GetSupportDirectory(), + '/', config, '/', + target->GetName(), ".swiftdeps")); + }(); - cmGeneratedFileStream output(mapFilePath); - output << this->Configs[config].SwiftOutputMap; - } + std::string mapFilePath = + cmStrCat(this->GeneratorTarget->GetSupportDirectory(), '/', config, '/', + "output-file-map.json"); + + // build the global target dependencies + // https://github.com/apple/swift/blob/master/docs/Driver.md#output-file-maps + Json::Value deps(Json::objectValue); + deps["swift-dependencies"] = targetSwiftDepsPath; + this->Configs[config].SwiftOutputMap[""] = deps; + + cmGeneratedFileStream output(mapFilePath); + output << this->Configs[config].SwiftOutputMap; + + // Add flag + this->LocalGenerator->AppendFlags(flags, "-output-file-map"); + this->LocalGenerator->AppendFlagEscape(flags, + ConvertToNinjaPath(mapFilePath)); } namespace { diff --git a/Source/cmNinjaTargetGenerator.h b/Source/cmNinjaTargetGenerator.h index 4b4cf8d361..c43b650d12 100644 --- a/Source/cmNinjaTargetGenerator.h +++ b/Source/cmNinjaTargetGenerator.h @@ -163,6 +163,9 @@ protected: void EmitSwiftDependencyInfo(cmSourceFile const* source, const std::string& config); + void GenerateSwiftOutputFileMap(const std::string& config, + std::string& flags); + void ExportObjectCompileCommand( std::string const& language, std::string const& sourceFileName, std::string const& objectDir, std::string const& objectFileName, diff --git a/Source/cmRulePlaceholderExpander.cxx b/Source/cmRulePlaceholderExpander.cxx index b63d11ce07..638bb42b38 100644 --- a/Source/cmRulePlaceholderExpander.cxx +++ b/Source/cmRulePlaceholderExpander.cxx @@ -119,11 +119,6 @@ std::string cmRulePlaceholderExpander::ExpandVariable( return this->ReplaceValues->SwiftModuleName; } } - if (this->ReplaceValues->SwiftOutputFileMap) { - if (variable == "SWIFT_OUTPUT_FILE_MAP") { - return this->ReplaceValues->SwiftOutputFileMap; - } - } if (this->ReplaceValues->SwiftSources) { if (variable == "SWIFT_SOURCES") { return this->ReplaceValues->SwiftSources; diff --git a/Source/cmRulePlaceholderExpander.h b/Source/cmRulePlaceholderExpander.h index 23ec405d06..5d1f199495 100644 --- a/Source/cmRulePlaceholderExpander.h +++ b/Source/cmRulePlaceholderExpander.h @@ -64,7 +64,7 @@ public: const char* SwiftLibraryName = nullptr; const char* SwiftModule = nullptr; const char* SwiftModuleName = nullptr; - const char* SwiftOutputFileMap = nullptr; + const char* SwiftOutputFileMapOption = nullptr; const char* SwiftSources = nullptr; const char* ISPCHeader = nullptr; const char* CudaCompileMode = nullptr; diff --git a/Source/cmState.cxx b/Source/cmState.cxx index 3d38e734af..17ee7f339c 100644 --- a/Source/cmState.cxx +++ b/Source/cmState.cxx @@ -786,6 +786,8 @@ std::string cmState::ModeToString(cmState::Mode mode) return "CTEST"; case CPack: return "CPACK"; + case Help: + return "HELP"; case Unknown: return "UNKNOWN"; } diff --git a/Source/cmState.h b/Source/cmState.h index 2d0c5210ca..9a17b22404 100644 --- a/Source/cmState.h +++ b/Source/cmState.h @@ -53,6 +53,7 @@ public: FindPackage, CTest, CPack, + Help }; enum class ProjectKind diff --git a/Source/cmTimestamp.cxx b/Source/cmTimestamp.cxx index 677fdb658e..7e47b4e51c 100644 --- a/Source/cmTimestamp.cxx +++ b/Source/cmTimestamp.cxx @@ -128,8 +128,8 @@ std::string cmTimestamp::CreateTimestampFromTimeT(time_t timeT, : static_cast<char>(0); if (c1 == '%' && c2 != 0) { - result += - this->AddTimestampComponent(c2, timeStruct, timeT, microseconds); + result += this->AddTimestampComponent(c2, timeStruct, timeT, utcFlag, + microseconds); ++i; } else { result += c1; @@ -179,7 +179,7 @@ time_t cmTimestamp::CreateUtcTimeTFromTm(struct tm& tm) const } std::string cmTimestamp::AddTimestampComponent( - char flag, struct tm& timeStruct, const time_t timeT, + char flag, struct tm& timeStruct, const time_t timeT, const bool utcFlag, const uint32_t microseconds) const { std::string formatString = cmStrCat('%', flag); @@ -203,6 +203,63 @@ std::string cmTimestamp::AddTimestampComponent( case 'Y': case '%': break; + case 'Z': +#if defined(__GLIBC__) + // 'struct tm' has the time zone, so strftime can honor UTC. + static_cast<void>(utcFlag); +#else + // 'struct tm' may not have the time zone, so strftime may + // use local time. Hard-code the UTC result. + if (utcFlag) { + return std::string("GMT"); + } +#endif + break; + case 'z': { +#if defined(__GLIBC__) + // 'struct tm' has the time zone, so strftime can honor UTC. + static_cast<void>(utcFlag); +#else + // 'struct tm' may not have the time zone, so strftime may + // use local time. Hard-code the UTC result. + if (utcFlag) { + return std::string("+0000"); + } +#endif +#ifndef _AIX + break; +#else + std::string xpg_sus_old; + bool const xpg_sus_was_set = + cmSystemTools::GetEnv("XPG_SUS_ENV", xpg_sus_old); + if (xpg_sus_was_set && xpg_sus_old == "ON") { + break; + } + xpg_sus_old = "XPG_SUS_ENV=" + xpg_sus_old; + + // On AIX systems, %z requires XPG_SUS_ENV=ON to work as desired. + cmSystemTools::PutEnv("XPG_SUS_ENV=ON"); + tzset(); + + char buffer[16]; + size_t size = strftime(buffer, sizeof(buffer), "%z", &timeStruct); + +# ifndef CMAKE_BOOTSTRAP + if (xpg_sus_was_set) { + cmSystemTools::PutEnv(xpg_sus_old); + } else { + cmSystemTools::UnsetEnv("XPG_SUS_ENV"); + } +# else + // No UnsetEnv during bootstrap. This is good enough for CMake itself. + cmSystemTools::PutEnv(xpg_sus_old); + static_cast<void>(xpg_sus_was_set); +# endif + tzset(); + + return std::string(buffer, size); +#endif + } case 's': // Seconds since UNIX epoch (midnight 1-jan-1970) { // Build a time_t for UNIX epoch and subtract from the input "timeT": diff --git a/Source/cmTimestamp.h b/Source/cmTimestamp.h index ada5006d45..05c6342cb2 100644 --- a/Source/cmTimestamp.h +++ b/Source/cmTimestamp.h @@ -32,6 +32,6 @@ private: time_t CreateUtcTimeTFromTm(struct tm& timeStruct) const; std::string AddTimestampComponent(char flag, struct tm& timeStruct, - time_t timeT, - uint32_t microseconds = 0) const; + time_t timeT, bool utcFlag, + uint32_t microseconds) const; }; diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 4cfb561b51..c9827133d8 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -3316,9 +3316,12 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( } } - if (this->ProjectType != VsProjectType::csproj && clOptions.IsManaged()) { + if (this->ProjectType != VsProjectType::csproj && + (clOptions.IsManaged() || clOptions.HasFlag("CLRSupport"))) { this->Managed = true; - std::string managedType = clOptions.GetFlag("CompileAsManaged"); + std::string managedType = clOptions.HasFlag("CompileAsManaged") + ? clOptions.GetFlag("CompileAsManaged") + : "Mixed"; if (managedType == "Safe" || managedType == "Pure") { // force empty calling convention if safe clr is used clOptions.AddFlag("CallingConvention", ""); diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 013a87b510..36c0089ff7 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -196,7 +196,7 @@ cmake::cmake(Role role, cmState::Mode mode, cmState::ProjectKind projectKind) this->AddProjectCommands(); } - if (mode == cmState::Project) { + if (mode == cmState::Project || mode == cmState::Help) { this->LoadEnvironmentPresets(); } @@ -1542,6 +1542,16 @@ void cmake::PrintTraceFormatVersion() } } +void cmake::SetTraceRedirect(cmake* other) +{ + this->Trace = other->Trace; + this->TraceExpand = other->TraceExpand; + this->TraceFormatVar = other->TraceFormatVar; + this->TraceOnlyThisSources = other->TraceOnlyThisSources; + + this->TraceRedirect = other; +} + bool cmake::SetDirectoriesFromFile(const std::string& arg) { // Check if the argument refers to a CMakeCache.txt or @@ -2060,6 +2070,10 @@ int cmake::HandleDeleteCacheVariables(const std::string& var) int cmake::Configure() { +#if !defined(CMAKE_BOOTSTRAP) + auto profilingRAII = this->CreateProfilingEntry("project", "configure"); +#endif + DiagLevel diagLevel; if (this->DiagLevels.count("deprecated") == 1) { @@ -2572,6 +2586,11 @@ int cmake::Generate() if (!this->GlobalGenerator) { return -1; } + +#if !defined(CMAKE_BOOTSTRAP) + auto profilingRAII = this->CreateProfilingEntry("project", "generate"); +#endif + if (!this->GlobalGenerator->Compute()) { return -1; } diff --git a/Source/cmake.h b/Source/cmake.h index 3183577131..2f7f7bd325 100644 --- a/Source/cmake.h +++ b/Source/cmake.h @@ -33,6 +33,7 @@ # include <cm3p/json/value.h> # include "cmCMakePresetsGraph.h" +# include "cmMakefileProfilingData.h" #endif class cmExternalMakefileProjectGeneratorFactory; @@ -41,9 +42,6 @@ class cmFileTimeCache; class cmGlobalGenerator; class cmGlobalGeneratorFactory; class cmMakefile; -#if !defined(CMAKE_BOOTSTRAP) -class cmMakefileProfilingData; -#endif class cmMessenger; class cmVariableWatch; struct cmBuildOptions; @@ -513,10 +511,19 @@ public: { return this->TraceOnlyThisSources; } - cmGeneratedFileStream& GetTraceFile() { return this->TraceFile; } + cmGeneratedFileStream& GetTraceFile() + { + if (this->TraceRedirect) { + return this->TraceRedirect->GetTraceFile(); + } + return this->TraceFile; + } void SetTraceFile(std::string const& file); void PrintTraceFormatVersion(); + //! Use trace from another ::cmake instance. + void SetTraceRedirect(cmake* other); + bool GetWarnUninitialized() const { return this->WarnUninitialized; } void SetWarnUninitialized(bool b) { this->WarnUninitialized = b; } bool GetWarnUnusedCli() const { return this->WarnUnusedCli; } @@ -630,6 +637,17 @@ public: #if !defined(CMAKE_BOOTSTRAP) cmMakefileProfilingData& GetProfilingOutput(); bool IsProfilingEnabled() const; + + template <typename... Args> + cm::optional<cmMakefileProfilingData::RAII> CreateProfilingEntry( + Args&&... args) + { + if (this->IsProfilingEnabled()) { + return cm::make_optional<cmMakefileProfilingData::RAII>( + this->GetProfilingOutput(), std::forward<Args>(args)...); + } + return cm::nullopt; + } #endif protected: @@ -688,6 +706,7 @@ private: bool TraceExpand = false; TraceFormat TraceFormatVar = TRACE_HUMAN; cmGeneratedFileStream TraceFile; + cmake* TraceRedirect = nullptr; bool WarnUninitialized = false; bool WarnUnusedCli = true; bool CheckSystemVars = false; diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx index 723932eb96..43bebc1889 100644 --- a/Source/cmakemain.cxx +++ b/Source/cmakemain.cxx @@ -208,7 +208,7 @@ int do_cmake(int ac, char const* const* av) doc.addCMakeStandardDocSections(); if (doc.CheckOptions(ac, av, "--")) { // Construct and print requested documentation. - cmake hcm(cmake::RoleInternal, cmState::Unknown); + cmake hcm(cmake::RoleInternal, cmState::Help); hcm.SetHomeDirectory(""); hcm.SetHomeOutputDirectory(""); hcm.AddCMakePaths(); diff --git a/Templates/MSBuild/FlagTables/v142_CL.json b/Templates/MSBuild/FlagTables/v142_CL.json index c76c040bc0..4f2dce8c77 100644 --- a/Templates/MSBuild/FlagTables/v142_CL.json +++ b/Templates/MSBuild/FlagTables/v142_CL.json @@ -56,6 +56,13 @@ "flags": [] }, { + "name": "CLRSupport", + "switch": "clr:netcore", + "comment": ".NET Core Runtime Support", + "value": "NetCore", + "flags": [] + }, + { "name": "WarningLevel", "switch": "W0", "comment": "Turn Off All Warnings", diff --git a/Templates/MSBuild/FlagTables/v143_CL.json b/Templates/MSBuild/FlagTables/v143_CL.json index 993fbf14d9..119e171c2a 100644 --- a/Templates/MSBuild/FlagTables/v143_CL.json +++ b/Templates/MSBuild/FlagTables/v143_CL.json @@ -56,6 +56,13 @@ "flags": [] }, { + "name": "CLRSupport", + "switch": "clr:netcore", + "comment": ".NET Core Runtime Support", + "value": "NetCore", + "flags": [] + }, + { "name": "WarningLevel", "switch": "W0", "comment": "Turn Off All Warnings", diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 6e35df90df..850e743d2f 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -271,14 +271,6 @@ if(BUILD_TESTING) find_package(Qt5Widgets QUIET NO_MODULE) endif() - if(NOT CMake_TEST_EXTERNAL_CMAKE) - add_subdirectory(CMakeLib) - endif() - add_subdirectory(CMakeOnly) - add_subdirectory(RunCMake) - - add_subdirectory(FindPackageModeMakefileTest) - # Collect a list of all test build directories. set(TEST_BUILD_DIRS) @@ -342,6 +334,21 @@ if(BUILD_TESTING) endif() endif() + if(CMake_TEST_XCODE_VERSION AND CMAKE_OSX_SDKVERSION AND CMAKE_OSX_SDKPRODUCT) + if((NOT CMake_TEST_XCODE_VERSION VERSION_LESS 6.1) AND + ((NOT CMAKE_OSX_SDKPRODUCT STREQUAL "Mac OS X") OR + (NOT CMAKE_OSX_SDKVERSION VERSION_LESS 10.10))) + if(CMAKE_GENERATOR STREQUAL "Xcode") + set(CMake_TEST_XCODE_SWIFT 1) + endif() + endif() + endif() + if(NOT DEFINED CMake_TEST_Swift) + if(CMAKE_Swift_COMPILER OR CMake_TEST_XCODE_SWIFT) + set(CMake_TEST_Swift 1) + endif() + endif() + # Use 1500 or CTEST_TEST_TIMEOUT for long test timeout value, # whichever is greater. set(CMAKE_LONG_TEST_TIMEOUT 1500) @@ -352,6 +359,14 @@ if(BUILD_TESTING) set(CMAKE_LONG_TEST_TIMEOUT 1500) endif() + if(NOT CMake_TEST_EXTERNAL_CMAKE) + add_subdirectory(CMakeLib) + endif() + add_subdirectory(CMakeOnly) + add_subdirectory(RunCMake) + + add_subdirectory(FindPackageModeMakefileTest) + add_test(NAME CMake.Copyright COMMAND ${CMAKE_CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/CMakeCopyright.cmake) @@ -380,16 +395,7 @@ if(BUILD_TESTING) ADD_TEST_MACRO(MissingSourceFile MissingSourceFile) set_tests_properties(MissingSourceFile PROPERTIES PASS_REGULAR_EXPRESSION "CMake Error at CMakeLists.txt:3 \\(add_executable\\):[ \r\n]*Cannot find source file:[ \r\n]*DoesNotExist/MissingSourceFile.c") - if(CMake_TEST_XCODE_VERSION AND CMAKE_OSX_SDKVERSION AND CMAKE_OSX_SDKPRODUCT) - if((NOT CMake_TEST_XCODE_VERSION VERSION_LESS 6.1) AND - ((NOT CMAKE_OSX_SDKPRODUCT STREQUAL "Mac OS X") OR - (NOT CMAKE_OSX_SDKVERSION VERSION_LESS 10.10))) - if(CMAKE_GENERATOR STREQUAL "Xcode") - set(CMake_TEST_XCODE_SWIFT 1) - endif() - endif() - endif() - if(CMAKE_Swift_COMPILER OR CMake_TEST_XCODE_SWIFT) + if(CMake_TEST_Swift) ADD_TEST_MACRO(SwiftOnly SwiftOnly) if(CMake_TEST_XCODE_SWIFT) ADD_TEST_MACRO(SwiftMix SwiftMix) diff --git a/Tests/CMakeTests/String-TIMESTAMP-TimeZone.cmake b/Tests/CMakeTests/String-TIMESTAMP-TimeZone.cmake new file mode 100644 index 0000000000..eb2eb424d7 --- /dev/null +++ b/Tests/CMakeTests/String-TIMESTAMP-TimeZone.cmake @@ -0,0 +1,22 @@ +string(TIMESTAMP output "%z") + +STRING(LENGTH output output_length) + +message("~${output}~") + +set(expected_output_length 6) + +if(NOT(${output_length} EQUAL ${expected_output_length})) + message(FATAL_ERROR "expected ${expected_output_length} entries in output with all specifiers; found ${output_length}") +endif() + +string(SUBSTRING ${output} 0 1 output0) +string(SUBSTRING ${output} 4 1 output4) + +if(NOT((${output0} STREQUAL "-") OR (${output0} STREQUAL "+"))) + message(FATAL_ERROR "expected output[0] equ '+' or '-'; found: '${output0}'") +endif() + +if(NOT((${output4} STREQUAL "0") OR (${output4} STREQUAL "5"))) + message(FATAL_ERROR "expected output[4] equ '0' or '5'; found: '${output4}'") +endif() diff --git a/Tests/CMakeTests/StringTest.cmake.in b/Tests/CMakeTests/StringTest.cmake.in index 154afa7f83..5f8b1117d2 100644 --- a/Tests/CMakeTests/StringTest.cmake.in +++ b/Tests/CMakeTests/StringTest.cmake.in @@ -44,6 +44,8 @@ set(TIMESTAMP-IncompleteSpecifier-RESULT 0) set(TIMESTAMP-IncompleteSpecifier-STDERR "~foobar%~") set(TIMESTAMP-AllSpecifiers-RESULT 0) set(TIMESTAMP-AllSpecifiers-STDERR "~[0-9]+(;[0-9]+)*~") +set(TIMESTAMP-TimeZone-RESULT 0) +set(TIMESTAMP-TimeZone-STDERR "~[-,+][0-9][0-9][0-9][0-9]~") set(TIMESTAMP-MonthWeekNames-RESULT 0) set(TIMESTAMP-MonthWeekNames-STDERR "~[^%]+;[^%]+~") set(TIMESTAMP-UnixTime-RESULT 0) @@ -75,6 +77,7 @@ check_cmake_test(String TIMESTAMP-IncompleteSpecifier TIMESTAMP-AllSpecifiers TIMESTAMP-MonthWeekNames + TIMESTAMP-TimeZone TIMESTAMP-UnixTime ) diff --git a/Tests/CheckSourceTree/check.cmake b/Tests/CheckSourceTree/check.cmake index c2e3529d65..a59ffb570d 100644 --- a/Tests/CheckSourceTree/check.cmake +++ b/Tests/CheckSourceTree/check.cmake @@ -3,6 +3,13 @@ if(DEFINED ENV{CTEST_REAL_HOME}) set(ENV{HOME} "$ENV{CTEST_REAL_HOME}") endif() +file(GLOB known_files + "${CMake_SOURCE_DIR}/Tests/JavaExportImport/InstallExport/hs_err_pid*.log" + ) +if(known_files) + file(REMOVE ${known_files}) +endif() + execute_process( COMMAND "${GIT_EXECUTABLE}" status WORKING_DIRECTORY "${CMake_SOURCE_DIR}" diff --git a/Tests/RunCMake/CMP0104/CMP0104-OLD-stderr.txt b/Tests/RunCMake/CMP0104/CMP0104-OLD-stderr.txt new file mode 100644 index 0000000000..66d301666a --- /dev/null +++ b/Tests/RunCMake/CMP0104/CMP0104-OLD-stderr.txt @@ -0,0 +1,10 @@ +^CMake Deprecation Warning at CMP0104-OLD.cmake:[0-9]+ \(cmake_policy\): + The OLD behavior for policy CMP0104 will be removed from a future version + of CMake. + + The cmake-policies\(7\) manual explains that the OLD behaviors of all + policies are deprecated and that a policy should be set to OLD only under + specific short-term circumstances. Projects should be ported to the NEW + behavior and not rely on setting a policy to OLD. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/CMP0106/CMP0106-OLD-stderr.txt b/Tests/RunCMake/CMP0106/CMP0106-OLD-stderr.txt new file mode 100644 index 0000000000..ef48d5ce4e --- /dev/null +++ b/Tests/RunCMake/CMP0106/CMP0106-OLD-stderr.txt @@ -0,0 +1,10 @@ +^CMake Deprecation Warning at CMP0106-OLD.cmake:[0-9]+ \(cmake_policy\): + The OLD behavior for policy CMP0106 will be removed from a future version + of CMake. + + The cmake-policies\(7\) manual explains that the OLD behaviors of all + policies are deprecated and that a policy should be set to OLD only under + specific short-term circumstances. Projects should be ported to the NEW + behavior and not rely on setting a policy to OLD. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index 3038ed8468..280a21a8a1 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -756,7 +756,8 @@ add_RunCMake_test(CheckCompilerFlag -DCMake_TEST_CUDA=${CMake_TEST_CUDA} add_RunCMake_test(CheckSourceCompiles -DCMake_TEST_CUDA=${CMake_TEST_CUDA} -DCMake_TEST_ISPC=${CMake_TEST_ISPC} -DCMAKE_Fortran_COMPILER_ID=${CMAKE_Fortran_COMPILER_ID} - -DCMake_TEST_HIP=${CMake_TEST_HIP}) + -DCMake_TEST_HIP=${CMake_TEST_HIP} + -DCMake_TEST_Swift=${CMake_TEST_Swift}) add_RunCMake_test(CheckSourceRuns -DCMake_TEST_CUDA=${CMake_TEST_CUDA} -DCMAKE_Fortran_COMPILER_ID=${CMAKE_Fortran_COMPILER_ID} -DCMake_TEST_HIP=${CMake_TEST_HIP}) diff --git a/Tests/RunCMake/CXXModules/RunCMakeTest.cmake b/Tests/RunCMake/CXXModules/RunCMakeTest.cmake index 3f17c1ff0e..921fabd35b 100644 --- a/Tests/RunCMake/CXXModules/RunCMakeTest.cmake +++ b/Tests/RunCMake/CXXModules/RunCMakeTest.cmake @@ -120,7 +120,9 @@ function (run_cxx_module_test directory) if (RunCMake_CXXModules_INSTALL) run_cmake_command("examples/${test_name}-install" "${CMAKE_COMMAND}" --build . --target install --config Debug) endif () - run_cmake_command("examples/${test_name}-test" "${CMAKE_CTEST_COMMAND}" -C Debug --output-on-failure) + if (NOT RunCMake_CXXModules_NO_TEST) + run_cmake_command("examples/${test_name}-test" "${CMAKE_CTEST_COMMAND}" -C Debug --output-on-failure) + endif () endfunction () string(REPLACE "," ";" CMake_TEST_MODULE_COMPILATION "${CMake_TEST_MODULE_COMPILATION}") @@ -132,6 +134,10 @@ if ("named" IN_LIST CMake_TEST_MODULE_COMPILATION) run_cxx_module_test(generated) run_cxx_module_test(public-req-private) run_cxx_module_test(deep-chain) + run_cxx_module_test(duplicate) + set(RunCMake_CXXModules_NO_TEST 1) + run_cxx_module_test(circular) + unset(RunCMake_CXXModules_NO_TEST) endif () # Tests which use named modules in shared libraries. diff --git a/Tests/RunCMake/CXXModules/examples/circular-build-result.txt b/Tests/RunCMake/CXXModules/examples/circular-build-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/circular-build-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CXXModules/examples/circular-build-stdout.txt b/Tests/RunCMake/CXXModules/examples/circular-build-stdout.txt new file mode 100644 index 0000000000..433b46145e --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/circular-build-stdout.txt @@ -0,0 +1 @@ +(Ninja generators)?(build stopped: dependency cycle:) diff --git a/Tests/RunCMake/CXXModules/examples/circular-stderr.txt b/Tests/RunCMake/CXXModules/examples/circular-stderr.txt new file mode 100644 index 0000000000..5e4392abc9 --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/circular-stderr.txt @@ -0,0 +1,9 @@ +CMake Warning \(dev\) at CMakeLists.txt:7 \(target_sources\): + CMake's C\+\+ module support is experimental. It is meant only for + experimentation and feedback to CMake developers. +This warning is for project developers. Use -Wno-dev to suppress it. + +CMake Warning \(dev\): + C\+\+20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP is + experimental. It is meant only for compiler developers to try. +This warning is for project developers. Use -Wno-dev to suppress it. diff --git a/Tests/RunCMake/CXXModules/examples/circular/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/circular/CMakeLists.txt new file mode 100644 index 0000000000..4d1997cd43 --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/circular/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.24) +project(cxx_modules_circular CXX) + +include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake") + +add_library(circular STATIC) +target_sources(circular + PUBLIC + FILE_SET CXX_MODULES + BASE_DIRS + "${CMAKE_CURRENT_SOURCE_DIR}" + FILES + circular-a.cppm + circular-b.cppm) +target_compile_features(circular PUBLIC cxx_std_20) diff --git a/Tests/RunCMake/CXXModules/examples/circular/circular-a.cppm b/Tests/RunCMake/CXXModules/examples/circular/circular-a.cppm new file mode 100644 index 0000000000..eea842b02a --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/circular/circular-a.cppm @@ -0,0 +1,6 @@ +export module a; +import b; + +export int a() { + return b(); +} diff --git a/Tests/RunCMake/CXXModules/examples/circular/circular-b.cppm b/Tests/RunCMake/CXXModules/examples/circular/circular-b.cppm new file mode 100644 index 0000000000..fc6dc428e8 --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/circular/circular-b.cppm @@ -0,0 +1,6 @@ +export module b; +import a; + +export int b() { + return a(); +} diff --git a/Tests/RunCMake/CXXModules/examples/duplicate-stderr.txt b/Tests/RunCMake/CXXModules/examples/duplicate-stderr.txt new file mode 100644 index 0000000000..5e4392abc9 --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/duplicate-stderr.txt @@ -0,0 +1,9 @@ +CMake Warning \(dev\) at CMakeLists.txt:7 \(target_sources\): + CMake's C\+\+ module support is experimental. It is meant only for + experimentation and feedback to CMake developers. +This warning is for project developers. Use -Wno-dev to suppress it. + +CMake Warning \(dev\): + C\+\+20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP is + experimental. It is meant only for compiler developers to try. +This warning is for project developers. Use -Wno-dev to suppress it. diff --git a/Tests/RunCMake/CXXModules/examples/duplicate/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/duplicate/CMakeLists.txt new file mode 100644 index 0000000000..27be7a8a02 --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/duplicate/CMakeLists.txt @@ -0,0 +1,39 @@ +cmake_minimum_required(VERSION 3.24) +project(cxx_modules_duplicate CXX) + +include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake") + +add_executable(duplicate) +target_sources(duplicate + PRIVATE + main.cxx + PRIVATE + FILE_SET CXX_MODULES + BASE_DIRS + "${CMAKE_CURRENT_SOURCE_DIR}" + FILES + duplicate.cxx) +target_compile_features(duplicate PRIVATE cxx_std_20) +target_compile_definitions(duplicate PRIVATE NDUPLICATE=1) + +add_executable(duplicate2) +target_sources(duplicate2 + PRIVATE + main.cxx + PRIVATE + FILE_SET CXX_MODULES + BASE_DIRS + "${CMAKE_CURRENT_SOURCE_DIR}" + FILES + duplicate.cxx) +target_compile_features(duplicate2 PRIVATE cxx_std_20) +target_compile_definitions(duplicate2 PRIVATE NDUPLICATE=2) + +add_test(NAME duplicate COMMAND duplicate) +set_property(TEST duplicate + PROPERTY + PASS_REGULAR_EXPRESSION "From duplicate #1") +add_test(NAME duplicate2 COMMAND duplicate2) +set_property(TEST duplicate2 + PROPERTY + PASS_REGULAR_EXPRESSION "From duplicate #2") diff --git a/Tests/RunCMake/CXXModules/examples/duplicate/duplicate.cxx b/Tests/RunCMake/CXXModules/examples/duplicate/duplicate.cxx new file mode 100644 index 0000000000..c0c820b6a4 --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/duplicate/duplicate.cxx @@ -0,0 +1,11 @@ +module; + +#include <iostream> + +export module duplicate; + +export int from_import() +{ + std::cerr << "From duplicate #" << NDUPLICATE << std::endl; + return 0; +} diff --git a/Tests/RunCMake/CXXModules/examples/duplicate/main.cxx b/Tests/RunCMake/CXXModules/examples/duplicate/main.cxx new file mode 100644 index 0000000000..c2c06369c8 --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/duplicate/main.cxx @@ -0,0 +1,6 @@ +import duplicate; + +int main(int argc, char* argv[]) +{ + return from_import(); +} diff --git a/Tests/RunCMake/CheckSourceCompiles/CheckSourceCompilesSwift.cmake b/Tests/RunCMake/CheckSourceCompiles/CheckSourceCompilesSwift.cmake new file mode 100644 index 0000000000..767fa69d71 --- /dev/null +++ b/Tests/RunCMake/CheckSourceCompiles/CheckSourceCompilesSwift.cmake @@ -0,0 +1,15 @@ +enable_language(Swift) +include(CheckSourceCompiles) + +set(Swift 1) # test that this is tolerated + +check_source_compiles(Swift "baz()" SHOULD_FAIL) + +if(SHOULD_FAIL) + message(SEND_ERROR "invalid Swift source didn't fail.") +endif() + +check_source_compiles(Swift "print(\"Hello, CMake\")" SHOULD_BUILD) +if(NOT SHOULD_BUILD) + message(SEND_ERROR "Test failed for valid Swift source.") +endif() diff --git a/Tests/RunCMake/CheckSourceCompiles/RunCMakeTest.cmake b/Tests/RunCMake/CheckSourceCompiles/RunCMakeTest.cmake index df77d3d09d..2ed3e3619f 100644 --- a/Tests/RunCMake/CheckSourceCompiles/RunCMakeTest.cmake +++ b/Tests/RunCMake/CheckSourceCompiles/RunCMakeTest.cmake @@ -31,3 +31,7 @@ endif() if(CMake_TEST_HIP) run_cmake(CheckSourceCompilesHIP) endif() + +if(CMake_TEST_Swift) + run_cmake(CheckSourceCompilesSwift) +endif() diff --git a/Tests/RunCMake/CommandLine/Envgen-bad-help-stderr.txt b/Tests/RunCMake/CommandLine/Envgen-bad-help-stderr.txt new file mode 100644 index 0000000000..cdfe857694 --- /dev/null +++ b/Tests/RunCMake/CommandLine/Envgen-bad-help-stderr.txt @@ -0,0 +1 @@ +CMake Error: CMAKE_GENERATOR was set but the specified generator doesn't exist. Using CMake default. diff --git a/Tests/RunCMake/CommandLine/Envgen-bad-help-stdout.txt b/Tests/RunCMake/CommandLine/Envgen-bad-help-stdout.txt new file mode 100644 index 0000000000..075c48c28f --- /dev/null +++ b/Tests/RunCMake/CommandLine/Envgen-bad-help-stdout.txt @@ -0,0 +1,2 @@ +Generators.* +\* (Unix Makefiles|Visual Studio).* diff --git a/Tests/RunCMake/CommandLine/Envgen-ninja-multi-help-stdout.txt b/Tests/RunCMake/CommandLine/Envgen-ninja-multi-help-stdout.txt new file mode 100644 index 0000000000..ece6e5db41 --- /dev/null +++ b/Tests/RunCMake/CommandLine/Envgen-ninja-multi-help-stdout.txt @@ -0,0 +1 @@ +\* Ninja Multi-Config[ ]+= Generates build-<Config>.ninja files. diff --git a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake index a2eeddf4aa..327b7725bb 100644 --- a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake +++ b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake @@ -349,6 +349,13 @@ function(run_EnvironmentGenerator) run_cmake_command(Envgen-bad ${CMAKE_COMMAND} -G) unset(ENV{CMAKE_GENERATOR}) + # Honor CMAKE_GENERATOR env var in --help output + set(ENV{CMAKE_GENERATOR} "Ninja Multi-Config") + run_cmake_command(Envgen-ninja-multi-help ${CMAKE_COMMAND} --help) + set(ENV{CMAKE_GENERATOR} "NoSuchGenerator") + run_cmake_command(Envgen-bad-help ${CMAKE_COMMAND} --help) + unset(ENV{CMAKE_GENERATOR}) + if(RunCMake_GENERATOR MATCHES "Visual Studio.*") set(ENV{CMAKE_GENERATOR} "${RunCMake_GENERATOR}") run_cmake_command(Envgen ${CMAKE_COMMAND} ${source_dir}) @@ -940,6 +947,7 @@ unset(RunCMake_TEST_OPTIONS) set(RunCMake_TEST_OPTIONS --trace) run_cmake(trace) +run_cmake(trace-try_compile) unset(RunCMake_TEST_OPTIONS) set(RunCMake_TEST_OPTIONS --trace-expand) @@ -952,6 +960,7 @@ unset(RunCMake_TEST_OPTIONS) set(RunCMake_TEST_OPTIONS --trace-redirect=${RunCMake_BINARY_DIR}/redirected.trace) run_cmake(trace-redirect) +run_cmake(trace-try_compile-redirect) unset(RunCMake_TEST_OPTIONS) set(RunCMake_TEST_OPTIONS --trace-redirect=/no/such/file.txt) diff --git a/Tests/RunCMake/CommandLine/trace-try_compile-redirect-check.cmake b/Tests/RunCMake/CommandLine/trace-try_compile-redirect-check.cmake new file mode 100644 index 0000000000..94a7c95b0e --- /dev/null +++ b/Tests/RunCMake/CommandLine/trace-try_compile-redirect-check.cmake @@ -0,0 +1,13 @@ +file(READ ${RunCMake_SOURCE_DIR}/trace-try_compile-stderr.txt expected_content) +string(REGEX REPLACE "\n+$" "" expected_content "${expected_content}") + +file(READ ${RunCMake_BINARY_DIR}/redirected.trace actual_content) +string(REGEX REPLACE "\r\n" "\n" actual_content "${actual_content}") +string(REGEX REPLACE "\n+$" "" actual_content "${actual_content}") +if(NOT "${actual_content}" MATCHES "${expected_content}") + set(RunCMake_TEST_FAILED + "Trace file content does not match that expected." + "Expected to match:\n${expected_content}\n" + "Actual content:\n${actual_content}\n" + ) +endif() diff --git a/Tests/RunCMake/CommandLine/trace-try_compile-redirect.cmake b/Tests/RunCMake/CommandLine/trace-try_compile-redirect.cmake new file mode 100644 index 0000000000..982cb89024 --- /dev/null +++ b/Tests/RunCMake/CommandLine/trace-try_compile-redirect.cmake @@ -0,0 +1,2 @@ +cmake_minimum_required(VERSION 3.24) +project(test C) diff --git a/Tests/RunCMake/CommandLine/trace-try_compile-stderr.txt b/Tests/RunCMake/CommandLine/trace-try_compile-stderr.txt new file mode 100644 index 0000000000..1674b8fd04 --- /dev/null +++ b/Tests/RunCMake/CommandLine/trace-try_compile-stderr.txt @@ -0,0 +1,4 @@ +.*Modules/CMakeDetermineCompilerABI.cmake\([0-9]+\): try_compile\([^)]+\) +.*Tests/RunCMake/CommandLine/trace-try_compile(-redirect)?-build/CMakeFiles/CMakeScratch/TryCompile-[^/]+/CMakeLists.txt\([0-9]+\): cmake_minimum_required.* +.*Tests/RunCMake/CommandLine/trace-try_compile(-redirect)?-build/CMakeFiles/CMakeScratch/TryCompile-[^/]+/CMakeLists.txt\([0-9]+\): project\(CMAKE_TRY_COMPILE.* +.*Tests/RunCMake/CommandLine/trace-try_compile(-redirect)?-build/CMakeFiles/CMakeScratch/TryCompile-[^/]+/CMakeLists.txt\([0-9]+\): add_executable\(cmTC_.* diff --git a/Tests/RunCMake/CommandLine/trace-try_compile.cmake b/Tests/RunCMake/CommandLine/trace-try_compile.cmake new file mode 100644 index 0000000000..982cb89024 --- /dev/null +++ b/Tests/RunCMake/CommandLine/trace-try_compile.cmake @@ -0,0 +1,2 @@ +cmake_minimum_required(VERSION 3.24) +project(test C) diff --git a/Tests/RunCMake/FindPkgConfig/FindPkgConfig_IMPORTED_TARGET.cmake b/Tests/RunCMake/FindPkgConfig/FindPkgConfig_IMPORTED_TARGET.cmake index f149d99174..69ab4da000 100644 --- a/Tests/RunCMake/FindPkgConfig/FindPkgConfig_IMPORTED_TARGET.cmake +++ b/Tests/RunCMake/FindPkgConfig/FindPkgConfig_IMPORTED_TARGET.cmake @@ -113,23 +113,33 @@ message(STATUS "Verifying target \"${tgt}\"") if (NOT TARGET ${tgt}) message(FATAL_ERROR "No import target for fake link options package") endif() -get_target_property(link_options ${tgt} INTERFACE_LINK_OPTIONS) -if (NOT link_options STREQUAL expected_link_options) - message(FATAL_ERROR - "Additional link options not present in INTERFACE_LINK_OPTIONS property\n" - "expected: \"${expected_link_options}\", but got \"${link_options}\"" - ) -endif() -get_target_property(inc_dirs ${tgt} INTERFACE_INCLUDE_DIRECTORIES) -set(expected_inc_dirs "/special" "/other" "/more") +# Some versions of pkg-config on Windows don't parse the Libs and Cflags +# correctly. The pkg-config that comes with Strawberry perl is one example. +# It appears to treat the dummymain part of Libs as a library and only returns +# -e. It also doesn't recognize "-isystem /other", presumably because it doesn't +# support having a space between "-isystem" and the directory after it (it does +# give us the "-isystem/more" flag). Since we can't reliably test for these, +# we don't enable these checks on Windows. +if(NOT WIN32) + get_target_property(link_options ${tgt} INTERFACE_LINK_OPTIONS) + if (NOT link_options STREQUAL expected_link_options) + message(FATAL_ERROR + "Additional link options not present in INTERFACE_LINK_OPTIONS property\n" + "expected: \"${expected_link_options}\", but got \"${link_options}\"" + ) + endif() -if (NOT inc_dirs STREQUAL expected_inc_dirs) - message(FATAL_ERROR - "Additional include directories not correctly present in INTERFACE_INCLUDE_DIRECTORIES property\n" - "expected: \"${expected_inc_dirs}\", got \"${inc_dirs}\"" - ) -endif () + get_target_property(inc_dirs ${tgt} INTERFACE_INCLUDE_DIRECTORIES) + set(expected_inc_dirs "/special" "/other" "/more") + + if (NOT inc_dirs STREQUAL expected_inc_dirs) + message(FATAL_ERROR + "Additional include directories not correctly present in INTERFACE_INCLUDE_DIRECTORIES property\n" + "expected: \"${expected_inc_dirs}\", got \"${inc_dirs}\"" + ) + endif () +endif() get_target_property(c_opts ${tgt} INTERFACE_COMPILE_OPTIONS) set(expected_c_opts "-DA-isystem/foo") # this is an invalid option, but a good testcase diff --git a/Tests/RunCMake/FindPkgConfig/FindPkgConfig_VERSION_OPERATORS.cmake b/Tests/RunCMake/FindPkgConfig/FindPkgConfig_VERSION_OPERATORS.cmake index 2a505c6a57..f7a9815b1c 100644 --- a/Tests/RunCMake/FindPkgConfig/FindPkgConfig_VERSION_OPERATORS.cmake +++ b/Tests/RunCMake/FindPkgConfig/FindPkgConfig_VERSION_OPERATORS.cmake @@ -20,14 +20,15 @@ Libs: -lcmakeinternalfakepackage # Always find the .pc file in the calls further below so that we can test that # the import target find_library() calls handle the NO...PATH options correctly -set(ENV{PKG_CONFIG_PATH} ${fakePkgDir}/lib/pkgconfig) +cmake_path(CONVERT "${fakePkgDir}/lib/pkgconfig" TO_NATIVE_PATH_LIST confPath) +set(ENV{PKG_CONFIG_PATH} "${confPath}") -pkg_check_modules(FakePackageGE REQUIRED QUIET "cmakeinternalfakepackage >= 8") +pkg_check_modules(FakePackageGE REQUIRED QUIET "cmakeinternalfakepackage>=8") if (NOT FakePackageGE_FOUND) message(FATAL_ERROR "fake package >= 8 not found") endif() -pkg_check_modules(FakePackageGE_FAIL QUIET "cmakeinternalfakepackage >= 8.10") +pkg_check_modules(FakePackageGE_FAIL QUIET "cmakeinternalfakepackage>=8.10") if (FakePackageGE_FAIL_FOUND) message(FATAL_ERROR "fake package >= 8.10 found") endif() @@ -37,17 +38,17 @@ if (NOT FakePackageLE_FOUND) message(FATAL_ERROR "fake package <= 9 not found") endif() -pkg_check_modules(FakePackageLE_FAIL QUIET "cmakeinternalfakepackage <= 8.1") +pkg_check_modules(FakePackageLE_FAIL QUIET "cmakeinternalfakepackage<=8.1") if (FakePackageLE_FAIL_FOUND) message(FATAL_ERROR "fake package <= 8.1 found") endif() -pkg_check_modules(FakePackageGT REQUIRED QUIET "cmakeinternalfakepackage > 8") +pkg_check_modules(FakePackageGT REQUIRED QUIET "cmakeinternalfakepackage>8") if (NOT FakePackageGT_FOUND) message(FATAL_ERROR "fake package > 8 not found") endif() -pkg_check_modules(FakePackageGT_FAIL QUIET "cmakeinternalfakepackage > 8.9") +pkg_check_modules(FakePackageGT_FAIL QUIET "cmakeinternalfakepackage>8.9") if (FakePackageGT_FAIL_FOUND) message(FATAL_ERROR "fake package > 8.9 found") endif() @@ -57,7 +58,7 @@ if (NOT FakePackageLT_FOUND) message(FATAL_ERROR "fake package < 9 not found") endif() -pkg_check_modules(FakePackageLT_FAIL QUIET "cmakeinternalfakepackage < 8.9") +pkg_check_modules(FakePackageLT_FAIL QUIET "cmakeinternalfakepackage<8.9") if (FakePackageLT_FAIL_FOUND) message(FATAL_ERROR "fake package < 8.9 found") endif() @@ -67,17 +68,17 @@ if (NOT FakePackageEQ_FOUND) message(FATAL_ERROR "fake package = 8.9 not found") endif() -pkg_check_modules(FakePackageEQ_FAIL QUIET "cmakeinternalfakepackage = 8.8") +pkg_check_modules(FakePackageEQ_FAIL QUIET "cmakeinternalfakepackage=8.8") if (FakePackageEQ_FAIL_FOUND) message(FATAL_ERROR "fake package = 8.8 found") endif() -pkg_check_modules(FakePackageEQ_INV QUIET "cmakeinternalfakepackage == 8.9") +pkg_check_modules(FakePackageEQ_INV QUIET "cmakeinternalfakepackage==8.9") if (FakePackageEQ_FAIL_FOUND) message(FATAL_ERROR "fake package == 8.9 found") endif() -pkg_check_modules(FakePackageLLT_INV QUIET "cmakeinternalfakepackage <<= 9") +pkg_check_modules(FakePackageLLT_INV QUIET "cmakeinternalfakepackage<<=9") if (FakePackageLLT_FAIL_FOUND) message(FATAL_ERROR "fake package <<= 9 found") endif() diff --git a/Tests/RunCMake/FindPkgConfig/RunCMakeTest.cmake b/Tests/RunCMake/FindPkgConfig/RunCMakeTest.cmake index 661ae3f30e..6b8e884127 100644 --- a/Tests/RunCMake/FindPkgConfig/RunCMakeTest.cmake +++ b/Tests/RunCMake/FindPkgConfig/RunCMakeTest.cmake @@ -7,13 +7,18 @@ set(ENV{CMAKE_FRAMEWORK_PATH} "") run_cmake(PkgConfigDoesNotExist) -run_cmake(FindPkgConfig_CMP0126_NEW) -run_cmake(FindPkgConfig_NO_PKGCONFIG_PATH) -run_cmake(FindPkgConfig_PKGCONFIG_PATH) -run_cmake(FindPkgConfig_PKGCONFIG_PATH_NO_CMAKE_PATH) -run_cmake(FindPkgConfig_PKGCONFIG_PATH_NO_CMAKE_ENVIRONMENT_PATH) +if(NOT WIN32) + # FIXME: The Windows implementation of these tests do not work. + # They are disabled until they can be updated to a working state. + run_cmake(FindPkgConfig_CMP0126_NEW) + run_cmake(FindPkgConfig_NO_PKGCONFIG_PATH) + run_cmake(FindPkgConfig_PKGCONFIG_PATH) + run_cmake(FindPkgConfig_PKGCONFIG_PATH_NO_CMAKE_PATH) + run_cmake(FindPkgConfig_PKGCONFIG_PATH_NO_CMAKE_ENVIRONMENT_PATH) + run_cmake(FindPkgConfig_GET_MATCHING_ARGN) +endif() + run_cmake(FindPkgConfig_extract_frameworks) -run_cmake(FindPkgConfig_GET_MATCHING_ARGN) if(APPLE) run_cmake(FindPkgConfig_extract_frameworks_target) diff --git a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake index f027e94eda..ed74896370 100644 --- a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake +++ b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake @@ -89,3 +89,10 @@ run_cmake(VsDotnetTargetFramework) run_cmake(VsDotnetTargetFrameworkVersion) run_cmake(VsNoCompileBatching) run_cmake(DebugInformationFormat) +run_cmake(VsCLREmpty) +run_cmake(VsCLRPure) +run_cmake(VsCLRSafe) + +if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 19.20) + run_cmake(VsCLRNetcore) +endif() diff --git a/Tests/RunCMake/VS10Project/VsCLREmpty-check.cmake b/Tests/RunCMake/VS10Project/VsCLREmpty-check.cmake new file mode 100644 index 0000000000..990da466a3 --- /dev/null +++ b/Tests/RunCMake/VS10Project/VsCLREmpty-check.cmake @@ -0,0 +1,24 @@ +set(vcProjectFile "${RunCMake_TEST_BINARY_DIR}/foo.vcxproj") +if(NOT EXISTS "${vcProjectFile}") + set(RunCMake_TEST_FAILED "Project file ${vcProjectFile} does not exist.") + return() +endif() + +set(propertyFound FALSE) +file(STRINGS "${vcProjectFile}" lines) +foreach(line IN LISTS lines) + if(line MATCHES "^ *<CompileAsManaged>(.*)</CompileAsManaged>$") + set(propertyFound TRUE) + set(expectedValue "true") + set(actualValue ${CMAKE_MATCH_1}) + if(NOT (${actualValue} STREQUAL ${expectedValue})) + set(RunCMake_TEST_FAILED "CompileAsManaged \"${actualValue}\" differs from expected value \"${expectedValue}\".") + return() + endif() + endif() +endforeach() + +if(NOT propertyFound) + set(RunCMake_TEST_FAILED "Property CompileAsManaged not found in project file.") + return() +endif() diff --git a/Tests/RunCMake/VS10Project/VsCLREmpty.cmake b/Tests/RunCMake/VS10Project/VsCLREmpty.cmake new file mode 100644 index 0000000000..a622f26a44 --- /dev/null +++ b/Tests/RunCMake/VS10Project/VsCLREmpty.cmake @@ -0,0 +1,6 @@ +enable_language(CXX) + +add_library(foo foo.cpp) + +set_target_properties(foo PROPERTIES + COMMON_LANGUAGE_RUNTIME "") diff --git a/Tests/RunCMake/VS10Project/VsCLRNetcore-check.cmake b/Tests/RunCMake/VS10Project/VsCLRNetcore-check.cmake new file mode 100644 index 0000000000..a5058d72d1 --- /dev/null +++ b/Tests/RunCMake/VS10Project/VsCLRNetcore-check.cmake @@ -0,0 +1,24 @@ +set(vcProjectFile "${RunCMake_TEST_BINARY_DIR}/foo.vcxproj") +if(NOT EXISTS "${vcProjectFile}") + set(RunCMake_TEST_FAILED "Project file ${vcProjectFile} does not exist.") + return() +endif() + +set(propertyFound FALSE) +file(STRINGS "${vcProjectFile}" lines) +foreach(line IN LISTS lines) + if(line MATCHES "^ *<CLRSupport>(.*)</CLRSupport>$") + set(propertyFound TRUE) + set(expectedValue "NetCore") + set(actualValue ${CMAKE_MATCH_1}) + if(NOT (${actualValue} STREQUAL ${expectedValue})) + set(RunCMake_TEST_FAILED "CLRSupport \"${actualValue}\" differs from expected value \"${expectedValue}\".") + return() + endif() + endif() +endforeach() + +if(NOT propertyFound) + set(RunCMake_TEST_FAILED "Property CLRSupport not found in project file.") + return() +endif() diff --git a/Tests/RunCMake/VS10Project/VsCLRNetcore.cmake b/Tests/RunCMake/VS10Project/VsCLRNetcore.cmake new file mode 100644 index 0000000000..c5ec2bcabe --- /dev/null +++ b/Tests/RunCMake/VS10Project/VsCLRNetcore.cmake @@ -0,0 +1,6 @@ +enable_language(CXX) + +add_library(foo foo.cpp) + +set_target_properties(foo PROPERTIES + COMMON_LANGUAGE_RUNTIME "netcore") diff --git a/Tests/RunCMake/VS10Project/VsCLRPure-check.cmake b/Tests/RunCMake/VS10Project/VsCLRPure-check.cmake new file mode 100644 index 0000000000..8ae73eb448 --- /dev/null +++ b/Tests/RunCMake/VS10Project/VsCLRPure-check.cmake @@ -0,0 +1,24 @@ +set(vcProjectFile "${RunCMake_TEST_BINARY_DIR}/foo.vcxproj") +if(NOT EXISTS "${vcProjectFile}") + set(RunCMake_TEST_FAILED "Project file ${vcProjectFile} does not exist.") + return() +endif() + +set(propertyFound FALSE) +file(STRINGS "${vcProjectFile}" lines) +foreach(line IN LISTS lines) + if(line MATCHES "^ *<CompileAsManaged>(.*)</CompileAsManaged>$") + set(propertyFound TRUE) + set(expectedValue "Pure") + set(actualValue ${CMAKE_MATCH_1}) + if(NOT (${actualValue} STREQUAL ${expectedValue})) + set(RunCMake_TEST_FAILED "CompileAsManaged \"${actualValue}\" differs from expected value \"${expectedValue}\".") + return() + endif() + endif() +endforeach() + +if(NOT propertyFound) + set(RunCMake_TEST_FAILED "Property CompileAsManaged not found in project file.") + return() +endif() diff --git a/Tests/RunCMake/VS10Project/VsCLRPure.cmake b/Tests/RunCMake/VS10Project/VsCLRPure.cmake new file mode 100644 index 0000000000..f919a1c65b --- /dev/null +++ b/Tests/RunCMake/VS10Project/VsCLRPure.cmake @@ -0,0 +1,6 @@ +enable_language(CXX) + +add_library(foo foo.cpp) + +set_target_properties(foo PROPERTIES + COMMON_LANGUAGE_RUNTIME "pure") diff --git a/Tests/RunCMake/VS10Project/VsCLRSafe-check.cmake b/Tests/RunCMake/VS10Project/VsCLRSafe-check.cmake new file mode 100644 index 0000000000..ebb1f71e56 --- /dev/null +++ b/Tests/RunCMake/VS10Project/VsCLRSafe-check.cmake @@ -0,0 +1,24 @@ +set(vcProjectFile "${RunCMake_TEST_BINARY_DIR}/foo.vcxproj") +if(NOT EXISTS "${vcProjectFile}") + set(RunCMake_TEST_FAILED "Project file ${vcProjectFile} does not exist.") + return() +endif() + +set(propertyFound FALSE) +file(STRINGS "${vcProjectFile}" lines) +foreach(line IN LISTS lines) + if(line MATCHES "^ *<CompileAsManaged>(.*)</CompileAsManaged>$") + set(propertyFound TRUE) + set(expectedValue "Safe") + set(actualValue ${CMAKE_MATCH_1}) + if(NOT (${actualValue} STREQUAL ${expectedValue})) + set(RunCMake_TEST_FAILED "CompileAsManaged \"${actualValue}\" differs from expected value \"${expectedValue}\".") + return() + endif() + endif() +endforeach() + +if(NOT propertyFound) + set(RunCMake_TEST_FAILED "Property CompileAsManaged not found in project file.") + return() +endif() diff --git a/Tests/RunCMake/VS10Project/VsCLRSafe.cmake b/Tests/RunCMake/VS10Project/VsCLRSafe.cmake new file mode 100644 index 0000000000..5f114bfa93 --- /dev/null +++ b/Tests/RunCMake/VS10Project/VsCLRSafe.cmake @@ -0,0 +1,6 @@ +enable_language(CXX) + +add_library(foo foo.cpp) + +set_target_properties(foo PROPERTIES + COMMON_LANGUAGE_RUNTIME "safe") diff --git a/Tests/RunCMake/alias_targets/duplicate-target-CMP0107-OLD-stderr.txt b/Tests/RunCMake/alias_targets/duplicate-target-CMP0107-OLD-stderr.txt new file mode 100644 index 0000000000..f5247caeda --- /dev/null +++ b/Tests/RunCMake/alias_targets/duplicate-target-CMP0107-OLD-stderr.txt @@ -0,0 +1,10 @@ +^CMake Deprecation Warning at duplicate-target-CMP0107-OLD.cmake:[0-9]+ \(cmake_policy\): + The OLD behavior for policy CMP0107 will be removed from a future version + of CMake. + + The cmake-policies\(7\) manual explains that the OLD behaviors of all + policies are deprecated and that a policy should be set to OLD only under + specific short-term circumstances. Projects should be ported to the NEW + behavior and not rely on setting a policy to OLD. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/export/Repeat-CMP0103-OLD-stderr.txt b/Tests/RunCMake/export/Repeat-CMP0103-OLD-stderr.txt new file mode 100644 index 0000000000..1183f86e99 --- /dev/null +++ b/Tests/RunCMake/export/Repeat-CMP0103-OLD-stderr.txt @@ -0,0 +1,10 @@ +^CMake Deprecation Warning at Repeat-CMP0103-OLD.cmake:[0-9]+ \(cmake_policy\): + The OLD behavior for policy CMP0103 will be removed from a future version + of CMake. + + The cmake-policies\(7\) manual explains that the OLD behaviors of all + policies are deprecated and that a policy should be set to OLD only under + specific short-term circumstances. Projects should be ported to the NEW + behavior and not rely on setting a policy to OLD. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/string/Timestamp-stderr.txt b/Tests/RunCMake/string/Timestamp-stderr.txt index f162f52992..c57bba6165 100644 --- a/Tests/RunCMake/string/Timestamp-stderr.txt +++ b/Tests/RunCMake/string/Timestamp-stderr.txt @@ -1 +1 @@ -RESULT=2005-08-07 23:19:49.000000 Sunday=Sun August=Aug 05 day=219 wd=0 week=32 w_iso=31 %I=11 epoch=1123456789 +^RESULT=2005-08-07 23:19:49.000000 Sunday=Sun August=Aug 05 day=219 wd=0 week=32 w_iso=31 %I=11 epoch=1123456789 TZ=GMT tz=\+0000$ diff --git a/Tests/RunCMake/string/Timestamp.cmake b/Tests/RunCMake/string/Timestamp.cmake index 531a237bdc..3d68b1a587 100644 --- a/Tests/RunCMake/string/Timestamp.cmake +++ b/Tests/RunCMake/string/Timestamp.cmake @@ -1,3 +1,3 @@ set(ENV{SOURCE_DATE_EPOCH} "1123456789") -string(TIMESTAMP RESULT "%Y-%m-%d %H:%M:%S.%f %A=%a %B=%b %y day=%j wd=%w week=%U w_iso=%V %%I=%I epoch=%s" UTC) +string(TIMESTAMP RESULT "%Y-%m-%d %H:%M:%S.%f %A=%a %B=%b %y day=%j wd=%w week=%U w_iso=%V %%I=%I epoch=%s TZ=%Z tz=%z" UTC) message("RESULT=${RESULT}") diff --git a/Tests/RunCMake/target_link_libraries/CMP0108-OLD-self-link-stderr.txt b/Tests/RunCMake/target_link_libraries/CMP0108-OLD-self-link-stderr.txt new file mode 100644 index 0000000000..07e9a9f8b6 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries/CMP0108-OLD-self-link-stderr.txt @@ -0,0 +1,10 @@ +^CMake Deprecation Warning at CMP0108-OLD-self-link.cmake:[0-9]+ \(cmake_policy\): + The OLD behavior for policy CMP0108 will be removed from a future version + of CMake. + + The cmake-policies\(7\) manual explains that the OLD behaviors of all + policies are deprecated and that a policy should be set to OLD only under + specific short-term circumstances. Projects should be ported to the NEW + behavior and not rely on setting a policy to OLD. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/SwiftMixLib/CMakeLists.txt b/Tests/SwiftMixLib/CMakeLists.txt index 40d3498d50..a52fc9491a 100644 --- a/Tests/SwiftMixLib/CMakeLists.txt +++ b/Tests/SwiftMixLib/CMakeLists.txt @@ -4,3 +4,6 @@ project(SwiftMixLib C CXX Swift) add_library(SwiftMixedLib lib.c lib.cpp lib.swift) add_executable(Swifty main.swift) target_link_libraries(Swifty PUBLIC SwiftMixedLib) + +add_executable(c_main main.c) +target_link_libraries(c_main PUBLIC SwiftMixedLib) diff --git a/Tests/SwiftMixLib/main.c b/Tests/SwiftMixLib/main.c new file mode 100644 index 0000000000..6ecf984d22 --- /dev/null +++ b/Tests/SwiftMixLib/main.c @@ -0,0 +1,3 @@ +int main(int argc, char* argv[]) +{ +} diff --git a/Tests/UseSWIG/BasicPerl/CMakeLists.txt b/Tests/UseSWIG/BasicPerl/CMakeLists.txt index 671d52984b..11517396ac 100644 --- a/Tests/UseSWIG/BasicPerl/CMakeLists.txt +++ b/Tests/UseSWIG/BasicPerl/CMakeLists.txt @@ -4,7 +4,9 @@ project(TestBasicPerl CXX) include(CTest) -set(language "perl") +if(NOT DEFINED language) + set(language "perl") +endif() include (../BasicConfiguration.cmake) diff --git a/Tests/UseSWIG/CMakeLists.txt b/Tests/UseSWIG/CMakeLists.txt index c76e8a0158..7c4925e841 100644 --- a/Tests/UseSWIG/CMakeLists.txt +++ b/Tests/UseSWIG/CMakeLists.txt @@ -20,6 +20,16 @@ add_test(NAME UseSWIG.LegacyPerl COMMAND --build-options ${build_options} --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION> ) +add_test(NAME UseSWIG.LegacyPerl5 COMMAND + ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION> + --build-and-test + "${CMake_SOURCE_DIR}/Tests/UseSWIG/LegacyPerl" + "${CMake_BINARY_DIR}/Tests/UseSWIG/LegacyPerl5" + ${build_generator_args} + --build-project TestLegacyPerl + --build-options ${build_options} -Dlanguage=perl5 + --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION> + ) include(CheckLanguage) check_language(CSharp) @@ -66,6 +76,16 @@ add_test(NAME UseSWIG.BasicPerl COMMAND --build-options ${build_options} --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION> ) +add_test(NAME UseSWIG.BasicPerl5 COMMAND + ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION> + --build-and-test + "${CMake_SOURCE_DIR}/Tests/UseSWIG/BasicPerl" + "${CMake_BINARY_DIR}/Tests/UseSWIG/BasicPerl5" + ${build_generator_args} + --build-project TestBasicPerl + --build-options ${build_options} -Dlanguage=perl5 + --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION> + ) if(SWIG_FOUND AND NOT SWIG_VERSION VERSION_LESS "4.0.2" AND CMAKE_GENERATOR MATCHES "Make|Ninja|Xcode|Visual Studio (1[1-9]|[2-9][0-9])") add_test(NAME UseSWIG.Depfile.BasicPython COMMAND @@ -89,6 +109,16 @@ if(SWIG_FOUND AND NOT SWIG_VERSION VERSION_LESS "4.0.2" --build-options ${build_options} -DSWIG_USE_SWIG_DEPENDENCIES=ON --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION> ) + add_test(NAME UseSWIG.Depfile.BasicPerl5 COMMAND + ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION> + --build-and-test + "${CMake_SOURCE_DIR}/Tests/UseSWIG/BasicPerl" + "${CMake_BINARY_DIR}/Tests/UseSWIG/BasicPerl5.Depfile" + ${build_generator_args} + --build-project TestBasicPerl + --build-options ${build_options} -DSWIG_USE_SWIG_DEPENDENCIES=ON -Dlanguage=perl5 + --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION> + ) endif() if (CMake_TEST_UseSWIG_Fortran) diff --git a/Tests/UseSWIG/LegacyPerl/CMakeLists.txt b/Tests/UseSWIG/LegacyPerl/CMakeLists.txt index 90d92f4eba..be0b4657e9 100644 --- a/Tests/UseSWIG/LegacyPerl/CMakeLists.txt +++ b/Tests/UseSWIG/LegacyPerl/CMakeLists.txt @@ -4,7 +4,9 @@ project(TestLegacyPerl CXX) include(CTest) -set(language "perl") +if(NOT DEFINED language) + set(language "perl") +endif() include (../LegacyConfiguration.cmake) diff --git a/Utilities/ClangTidyModule/CMakeLists.txt b/Utilities/ClangTidyModule/CMakeLists.txt new file mode 100644 index 0000000000..6be13d608d --- /dev/null +++ b/Utilities/ClangTidyModule/CMakeLists.txt @@ -0,0 +1,27 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. +cmake_minimum_required(VERSION 3.13) +project(CMakeClangTidyModule C CXX) + +get_filename_component(tmp "${CMAKE_CURRENT_SOURCE_DIR}" PATH) +get_filename_component(CMake_SOURCE_DIR "${tmp}" PATH) + +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(Clang REQUIRED) + +add_library(cmake-clang-tidy-module MODULE + Module.cxx + + UseCmstrlenCheck.cxx + UseCmstrlenCheck.h + ) +target_include_directories(cmake-clang-tidy-module PRIVATE ${CLANG_INCLUDE_DIRS}) +target_link_libraries(cmake-clang-tidy-module PRIVATE clang-tidy) + +option(RUN_TESTS "Run the tests for the clang-tidy module" OFF) +if(RUN_TESTS) + enable_testing() + add_subdirectory(Tests) +endif() diff --git a/Utilities/ClangTidyModule/Module.cxx b/Utilities/ClangTidyModule/Module.cxx new file mode 100644 index 0000000000..a35c3367a3 --- /dev/null +++ b/Utilities/ClangTidyModule/Module.cxx @@ -0,0 +1,24 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include <clang-tidy/ClangTidyModule.h> +#include <clang-tidy/ClangTidyModuleRegistry.h> + +#include "UseCmstrlenCheck.h" + +namespace clang { +namespace tidy { +namespace cmake { +class CMakeClangTidyModule : public ClangTidyModule +{ +public: + void addCheckFactories(ClangTidyCheckFactories& CheckFactories) override + { + CheckFactories.registerCheck<UseCmstrlenCheck>("cmake-use-cmstrlen"); + } +}; + +static ClangTidyModuleRegistry::Add<CMakeClangTidyModule> X( + "cmake-clang-tidy", "Adds lint checks for the CMake code base."); +} +} +} diff --git a/Utilities/ClangTidyModule/Tests/CMakeLists.txt b/Utilities/ClangTidyModule/Tests/CMakeLists.txt new file mode 100644 index 0000000000..42027ed125 --- /dev/null +++ b/Utilities/ClangTidyModule/Tests/CMakeLists.txt @@ -0,0 +1,13 @@ +configure_file("${CMake_SOURCE_DIR}/.clang-format" ".clang-format" COPYONLY) + +function(add_run_clang_tidy_test check_name) + add_test(NAME "RunClangTidy.${check_name}" COMMAND ${CMAKE_COMMAND} + "-DCLANG_TIDY_COMMAND=$<TARGET_FILE:clang-tidy>" + "-DCLANG_TIDY_MODULE=$<TARGET_FILE:cmake-clang-tidy-module>" + "-DCHECK_NAME=${check_name}" + "-DRunClangTidy_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}" + -P "${CMAKE_CURRENT_SOURCE_DIR}/RunClangTidy.cmake" + ) +endfunction() + +add_run_clang_tidy_test(cmake-use-cmstrlen) diff --git a/Utilities/ClangTidyModule/Tests/RunClangTidy.cmake b/Utilities/ClangTidyModule/Tests/RunClangTidy.cmake new file mode 100644 index 0000000000..486d592e2c --- /dev/null +++ b/Utilities/ClangTidyModule/Tests/RunClangTidy.cmake @@ -0,0 +1,67 @@ +set(config_arg) +if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}.clang-tidy") + set(config_arg "--config-file=${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}.clang-tidy") +endif() + +foreach(o out err) + if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}-std${o}.txt") + file(READ "${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}-std${o}.txt" expect_std${o}) + string(REGEX REPLACE "\n+$" "" expect_std${o} "${expect_std${o}}") + else() + set(expect_std${o} "") + endif() +endforeach() + +set(source_file "${RunClangTidy_BINARY_DIR}/${CHECK_NAME}.cxx") +configure_file("${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}.cxx" "${source_file}" COPYONLY) + +set(command + "${CLANG_TIDY_COMMAND}" + "--load=${CLANG_TIDY_MODULE}" + "--checks=-*,${CHECK_NAME}" + "--fix" + "--format-style=file" + ${config_arg} + "${source_file}" + -- + ) +execute_process( + COMMAND ${command} + RESULT_VARIABLE result + OUTPUT_VARIABLE actual_stdout + ERROR_VARIABLE actual_stderr + ) +string(REPLACE "${RunClangTidy_BINARY_DIR}/" "" actual_stdout "${actual_stdout}") + +set(RunClangTidy_TEST_FAILED) + +if(NOT result EQUAL 0) + string(APPEND RunClangTidy_TEST_FAILED "Expected result: 0, actual result: ${result}\n") +endif() + +foreach(o out err) + string(REGEX REPLACE "\n+$" "" actual_std${o} "${actual_std${o}}") + if(NOT actual_std${o} STREQUAL expect_std${o}) + string(REPLACE "\n" "\n " expect_std${o}_formatted " ${expect_std${o}}") + string(REPLACE "\n" "\n " actual_std${o}_formatted " ${actual_std${o}}") + string(APPEND RunClangTidy_TEST_FAILED "Expected std${o}:\n${expect_std${o}_formatted}\nActual std${o}:\n${actual_std${o}_formatted}\n") + endif() +endforeach() + +if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}-fixit.cxx") + set(expect_fixit_file "${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}-fixit.cxx") +else() + set(expect_fixit_file "${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}.cxx") +endif() +file(READ "${expect_fixit_file}" expect_fixit) +file(READ "${source_file}" actual_fixit) +if(NOT expect_fixit STREQUAL actual_fixit) + string(REPLACE "\n" "\n " expect_fixit_formatted " ${expect_fixit}") + string(REPLACE "\n" "\n " actual_fixit_formatted " ${actual_fixit}") + string(APPEND RunClangTidy_TEST_FAILED "Expected fixit:\n${expect_fixit_formatted}\nActual fixit:\n${actual_fixit_formatted}\n") +endif() + +if(RunClangTidy_TEST_FAILED) + string(REPLACE ";" " " command_formatted "${command}") + message(FATAL_ERROR "Command:\n ${command_formatted}\n${RunClangTidy_TEST_FAILED}") +endif() diff --git a/Utilities/ClangTidyModule/Tests/cmake-use-cmstrlen-fixit.cxx b/Utilities/ClangTidyModule/Tests/cmake-use-cmstrlen-fixit.cxx new file mode 100644 index 0000000000..c93d5576fb --- /dev/null +++ b/Utilities/ClangTidyModule/Tests/cmake-use-cmstrlen-fixit.cxx @@ -0,0 +1,37 @@ +#include <cstring> + +template <size_t N> +constexpr size_t cmStrLen(const char (&/*str*/)[N]) +{ + return N - 1; +} + +namespace ns1 { +using std::strlen; +} + +namespace ns2 { +std::size_t strlen(const char* str) +{ + return std::strlen(str); +} +} + +int main() +{ + // String variable used for calling strlen() on a variable + auto s0 = "howdy"; + + // Correction needed + (void)cmStrLen("Hello"); + (void)cmStrLen("Goodbye"); + (void)cmStrLen("Hola"); + (void)cmStrLen("Bonjour"); + + // No correction needed + (void)ns2::strlen("Salve"); + (void)cmStrLen("Konnichiwa"); + (void)strlen(s0); + + return 0; +} diff --git a/Utilities/ClangTidyModule/Tests/cmake-use-cmstrlen-stderr.txt b/Utilities/ClangTidyModule/Tests/cmake-use-cmstrlen-stderr.txt new file mode 100644 index 0000000000..9d9d2ed3c9 --- /dev/null +++ b/Utilities/ClangTidyModule/Tests/cmake-use-cmstrlen-stderr.txt @@ -0,0 +1,2 @@ +4 warnings generated. +clang-tidy applied 4 of 4 suggested fixes. diff --git a/Utilities/ClangTidyModule/Tests/cmake-use-cmstrlen-stdout.txt b/Utilities/ClangTidyModule/Tests/cmake-use-cmstrlen-stdout.txt new file mode 100644 index 0000000000..6c52ad5af9 --- /dev/null +++ b/Utilities/ClangTidyModule/Tests/cmake-use-cmstrlen-stdout.txt @@ -0,0 +1,20 @@ +cmake-use-cmstrlen.cxx:26:9: warning: use cmStrLen() for string literals [cmake-use-cmstrlen] + (void)strlen("Hello"); + ^~~~~~ + cmStrLen +cmake-use-cmstrlen.cxx:26:9: note: FIX-IT applied suggested code changes +cmake-use-cmstrlen.cxx:27:9: warning: use cmStrLen() for string literals [cmake-use-cmstrlen] + (void)::strlen("Goodbye"); + ^~~~~~~~ + cmStrLen +cmake-use-cmstrlen.cxx:27:9: note: FIX-IT applied suggested code changes +cmake-use-cmstrlen.cxx:28:9: warning: use cmStrLen() for string literals [cmake-use-cmstrlen] + (void)std::strlen("Hola"); + ^~~~~~~~~~~ + cmStrLen +cmake-use-cmstrlen.cxx:28:9: note: FIX-IT applied suggested code changes +cmake-use-cmstrlen.cxx:29:9: warning: use cmStrLen() for string literals [cmake-use-cmstrlen] + (void)ns1::strlen("Bonjour"); + ^~~~~~~~~~~ + cmStrLen +cmake-use-cmstrlen.cxx:29:9: note: FIX-IT applied suggested code changes diff --git a/Utilities/ClangTidyModule/Tests/cmake-use-cmstrlen.cxx b/Utilities/ClangTidyModule/Tests/cmake-use-cmstrlen.cxx new file mode 100644 index 0000000000..f36262b5ea --- /dev/null +++ b/Utilities/ClangTidyModule/Tests/cmake-use-cmstrlen.cxx @@ -0,0 +1,37 @@ +#include <cstring> + +template <size_t N> +constexpr size_t cmStrLen(const char (&/*str*/)[N]) +{ + return N - 1; +} + +namespace ns1 { +using std::strlen; +} + +namespace ns2 { +std::size_t strlen(const char* str) +{ + return std::strlen(str); +} +} + +int main() +{ + // String variable used for calling strlen() on a variable + auto s0 = "howdy"; + + // Correction needed + (void)strlen("Hello"); + (void)::strlen("Goodbye"); + (void)std::strlen("Hola"); + (void)ns1::strlen("Bonjour"); + + // No correction needed + (void)ns2::strlen("Salve"); + (void)cmStrLen("Konnichiwa"); + (void)strlen(s0); + + return 0; +} diff --git a/Utilities/ClangTidyModule/UseCmstrlenCheck.cxx b/Utilities/ClangTidyModule/UseCmstrlenCheck.cxx new file mode 100644 index 0000000000..590d260b4e --- /dev/null +++ b/Utilities/ClangTidyModule/UseCmstrlenCheck.cxx @@ -0,0 +1,34 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "UseCmstrlenCheck.h" + +#include <clang/ASTMatchers/ASTMatchFinder.h> + +namespace clang { +namespace tidy { +namespace cmake { +using namespace ast_matchers; + +UseCmstrlenCheck::UseCmstrlenCheck(StringRef Name, ClangTidyContext* Context) + : ClangTidyCheck(Name, Context) +{ +} + +void UseCmstrlenCheck::registerMatchers(MatchFinder* Finder) +{ + Finder->addMatcher(callExpr(callee(functionDecl(hasName("::strlen"))), + callee(expr().bind("callee")), + hasArgument(0, stringLiteral())), + this); +} + +void UseCmstrlenCheck::check(const MatchFinder::MatchResult& Result) +{ + const Expr* Node = Result.Nodes.getNodeAs<Expr>("callee"); + + this->diag(Node->getBeginLoc(), "use cmStrLen() for string literals") + << FixItHint::CreateReplacement(Node->getSourceRange(), "cmStrLen"); +} +} +} +} diff --git a/Utilities/ClangTidyModule/UseCmstrlenCheck.h b/Utilities/ClangTidyModule/UseCmstrlenCheck.h new file mode 100644 index 0000000000..08f77c23a9 --- /dev/null +++ b/Utilities/ClangTidyModule/UseCmstrlenCheck.h @@ -0,0 +1,21 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#include <clang-tidy/ClangTidyCheck.h> +#include <clang/ASTMatchers/ASTMatchFinder.h> + +namespace clang { +namespace tidy { +namespace cmake { +class UseCmstrlenCheck : public ClangTidyCheck +{ +public: + UseCmstrlenCheck(StringRef Name, ClangTidyContext* Context); + void registerMatchers(ast_matchers::MatchFinder* Finder) override; + + void check(const ast_matchers::MatchFinder::MatchResult& Result) override; +}; +} +} +} diff --git a/Utilities/Doxygen/CMakeLists.txt b/Utilities/Doxygen/CMakeLists.txt index bc163500b2..b084dd5b98 100644 --- a/Utilities/Doxygen/CMakeLists.txt +++ b/Utilities/Doxygen/CMakeLists.txt @@ -3,7 +3,7 @@ if(NOT CMake_SOURCE_DIR) set(CMakeDeveloperReference_STANDALONE 1) - cmake_minimum_required(VERSION 3.13...3.23 FATAL_ERROR) + cmake_minimum_required(VERSION 3.13...3.24 FATAL_ERROR) get_filename_component(tmp "${CMAKE_CURRENT_SOURCE_DIR}" PATH) get_filename_component(CMake_SOURCE_DIR "${tmp}" PATH) include(${CMake_SOURCE_DIR}/Modules/CTestUseLaunchers.cmake) diff --git a/Utilities/Sphinx/CMakeLists.txt b/Utilities/Sphinx/CMakeLists.txt index 886f4e0300..bd2f3055b5 100644 --- a/Utilities/Sphinx/CMakeLists.txt +++ b/Utilities/Sphinx/CMakeLists.txt @@ -3,7 +3,7 @@ if(NOT CMake_SOURCE_DIR) set(CMakeHelp_STANDALONE 1) - cmake_minimum_required(VERSION 3.13...3.23 FATAL_ERROR) + cmake_minimum_required(VERSION 3.13...3.24 FATAL_ERROR) get_filename_component(tmp "${CMAKE_CURRENT_SOURCE_DIR}" PATH) get_filename_component(CMake_SOURCE_DIR "${tmp}" PATH) include(${CMake_SOURCE_DIR}/Modules/CTestUseLaunchers.cmake) diff --git a/Utilities/Sphinx/cmake.py b/Utilities/Sphinx/cmake.py index c7b1233509..47e4909ba0 100644 --- a/Utilities/Sphinx/cmake.py +++ b/Utilities/Sphinx/cmake.py @@ -475,3 +475,4 @@ def setup(app): app.add_transform(CMakeTransform) app.add_transform(CMakeXRefTransform) app.add_domain(CMakeDomain) + return {"parallel_read_safe": True} |