diff options
46 files changed, 282 insertions, 71 deletions
diff --git a/.clang-tidy b/.clang-tidy index 18aa86e..7ee8bf0 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -34,6 +34,7 @@ readability-*,\ -readability-suspicious-call-argument,\ -readability-uppercase-literal-suffix,\ cmake-*,\ +-cmake-ostringstream-use-cmstrcat,\ -cmake-use-bespoke-enum-class,\ " HeaderFilterRegex: 'Source/cm[^/]*\.(h|hxx|cxx)$' diff --git a/Help/command/project.rst b/Help/command/project.rst index 8f32fa3..4e57d09 100644 --- a/Help/command/project.rst +++ b/Help/command/project.rst @@ -188,5 +188,6 @@ call exists, CMake will issue a warning and pretend there is a Call the ``project()`` command near the top of the top-level ``CMakeLists.txt``, but *after* calling :command:`cmake_minimum_required`. It is important to establish version and policy settings before invoking - other commands whose behavior they may affect. + other commands whose behavior they may affect and for this reason the + ``project()`` command will issue a warning if this order is not kept. See also policy :policy:`CMP0000`. diff --git a/Help/manual/cmake.1.rst b/Help/manual/cmake.1.rst index daa2e58..dc51383 100644 --- a/Help/manual/cmake.1.rst +++ b/Help/manual/cmake.1.rst @@ -848,17 +848,21 @@ Available commands are: .. program:: cmake-E -.. option:: copy <file>... <destination> +.. option:: copy <file>... <destination>, copy -t <destination> <file>... Copy files to ``<destination>`` (either file or directory). - If multiple files are specified, the ``<destination>`` must be - directory and it must exist. Wildcards are not supported. - ``copy`` does follow symlinks. That means it does not copy symlinks, - but the files or directories it point to. + If multiple files are specified, or if ``-t`` is specified, the + ``<destination>`` must be directory and it must exist. If ``-t`` is not + specified, the last argument is assumed to be the ``<destination>``. + Wildcards are not supported. ``copy`` does follow symlinks. That means it + does not copy symlinks, but the files or directories it point to. .. versionadded:: 3.5 Support for multiple input files. + .. versionadded:: 3.26 + Support for ``-t`` argument. + .. option:: copy_directory <dir>... <destination> Copy content of ``<dir>...`` directories to ``<destination>`` directory. diff --git a/Help/release/dev/cmake-E-copy-t-arg.rst b/Help/release/dev/cmake-E-copy-t-arg.rst new file mode 100644 index 0000000..ca897d3 --- /dev/null +++ b/Help/release/dev/cmake-E-copy-t-arg.rst @@ -0,0 +1,4 @@ +cmake-E-copy-t-arg +------------------ + +* The :option:`cmake -E copy <cmake-E copy>` argument now supports a ``-t`` argument. diff --git a/Help/release/dev/top-level-command-order.rst b/Help/release/dev/top-level-command-order.rst new file mode 100644 index 0000000..07f87fb --- /dev/null +++ b/Help/release/dev/top-level-command-order.rst @@ -0,0 +1,6 @@ +top-level-command-order +----------------------- + +* The top-level :command:`project` call will now emit an author warning if the + documented command order in relation to :command:`cmake_minimum_required` is + not respected. diff --git a/Modules/CMakeDetermineSystem.cmake b/Modules/CMakeDetermineSystem.cmake index 2c2c2ac..94e92e8 100644 --- a/Modules/CMakeDetermineSystem.cmake +++ b/Modules/CMakeDetermineSystem.cmake @@ -33,20 +33,32 @@ # find out on which system cmake runs if(CMAKE_HOST_UNIX) - find_program(CMAKE_UNAME uname /bin /usr/bin /usr/local/bin ) + find_program(CMAKE_UNAME NAMES uname PATHS /bin /usr/bin /usr/local/bin) if(CMAKE_UNAME) if(CMAKE_HOST_SYSTEM_NAME STREQUAL "AIX") - exec_program(${CMAKE_UNAME} ARGS -v OUTPUT_VARIABLE _CMAKE_HOST_SYSTEM_MAJOR_VERSION) - exec_program(${CMAKE_UNAME} ARGS -r OUTPUT_VARIABLE _CMAKE_HOST_SYSTEM_MINOR_VERSION) + execute_process(COMMAND ${CMAKE_UNAME} -v + OUTPUT_VARIABLE _CMAKE_HOST_SYSTEM_MAJOR_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET) + execute_process(COMMAND ${CMAKE_UNAME} -r + OUTPUT_VARIABLE _CMAKE_HOST_SYSTEM_MINOR_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET) set(CMAKE_HOST_SYSTEM_VERSION "${_CMAKE_HOST_SYSTEM_MAJOR_VERSION}.${_CMAKE_HOST_SYSTEM_MINOR_VERSION}") unset(_CMAKE_HOST_SYSTEM_MAJOR_VERSION) unset(_CMAKE_HOST_SYSTEM_MINOR_VERSION) else() - exec_program(${CMAKE_UNAME} ARGS -r OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_VERSION) + execute_process(COMMAND ${CMAKE_UNAME} -r + OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET) endif() if(CMAKE_HOST_SYSTEM_NAME MATCHES "Linux|CYGWIN.*|MSYS.*|^GNU$|Android") - exec_program(${CMAKE_UNAME} ARGS -m OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_PROCESSOR - RETURN_VALUE val) + execute_process(COMMAND ${CMAKE_UNAME} -m + OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_PROCESSOR + RESULT_VARIABLE val + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET) elseif(CMAKE_HOST_SYSTEM_NAME MATCHES "Darwin") # If we are running on Apple Silicon, honor CMAKE_APPLE_SILICON_PROCESSOR. if(DEFINED CMAKE_APPLE_SILICON_PROCESSOR) @@ -74,8 +86,11 @@ if(CMAKE_HOST_UNIX) if(_CMAKE_APPLE_SILICON_PROCESSOR) set(CMAKE_HOST_SYSTEM_PROCESSOR "${_CMAKE_APPLE_SILICON_PROCESSOR}") else() - exec_program(${CMAKE_UNAME} ARGS -m OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_PROCESSOR - RETURN_VALUE val) + execute_process(COMMAND ${CMAKE_UNAME} -m + OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_PROCESSOR + RESULT_VARIABLE val + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET) endif() unset(_CMAKE_APPLE_SILICON_PROCESSOR) if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "Power Macintosh") @@ -83,14 +98,23 @@ if(CMAKE_HOST_UNIX) set(CMAKE_HOST_SYSTEM_PROCESSOR "powerpc") endif() elseif(CMAKE_HOST_SYSTEM_NAME MATCHES "OpenBSD") - exec_program(arch ARGS -s OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_PROCESSOR - RETURN_VALUE val) + execute_process(COMMAND arch -s + OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_PROCESSOR + RESULT_VARIABLE val + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET) else() - exec_program(${CMAKE_UNAME} ARGS -p OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_PROCESSOR - RETURN_VALUE val) + execute_process(COMMAND ${CMAKE_UNAME} -p + OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_PROCESSOR + RESULT_VARIABLE val + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET) if("${val}" GREATER 0) - exec_program(${CMAKE_UNAME} ARGS -m OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_PROCESSOR - RETURN_VALUE val) + execute_process(COMMAND ${CMAKE_UNAME} -m + OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_PROCESSOR + RESULT_VARIABLE val + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET) endif() endif() # check the return of the last uname -m or -p diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index fbd5c69..359576c 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,7 +1,7 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 25) -set(CMake_VERSION_PATCH 20221114) +set(CMake_VERSION_PATCH 20221115) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) diff --git a/Source/cmCommandLineArgument.h b/Source/cmCommandLineArgument.h index 33c91bc..003e972 100644 --- a/Source/cmCommandLineArgument.h +++ b/Source/cmCommandLineArgument.h @@ -2,6 +2,8 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #pragma once +#include <cm/optional> + #include "cmStringAlgorithms.h" #include "cmSystemTools.h" @@ -250,6 +252,15 @@ private: return true; }; } + + static std::function<bool(const std::string&, CallState...)> + generateSetToValue(cm::optional<std::string>& value1) + { + return [&value1](const std::string& arg, CallState&&...) -> bool { + value1 = arg; + return true; + }; + } }; std::string extract_single_value(std::string const& input, diff --git a/Source/cmProjectCommand.cxx b/Source/cmProjectCommand.cxx index 249fe2d..4d1ccfe 100644 --- a/Source/cmProjectCommand.cxx +++ b/Source/cmProjectCommand.cxx @@ -34,6 +34,15 @@ bool cmProjectCommand(std::vector<std::string> const& args, } cmMakefile& mf = status.GetMakefile(); + if (mf.IsRootMakefile() && + !mf.GetDefinition("CMAKE_MINIMUM_REQUIRED_VERSION")) { + mf.IssueMessage( + MessageType::AUTHOR_WARNING, + "cmake_minimum_required() should be called prior to this top-level " + "project() call. Please see the cmake-commands(7) manual for usage " + "documentation of both commands."); + } + if (!IncludeByVariable(status, "CMAKE_PROJECT_INCLUDE_BEFORE")) { return false; } diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx index 43bebc1..9f23667 100644 --- a/Source/cmakemain.cxx +++ b/Source/cmakemain.cxx @@ -522,25 +522,8 @@ int do_build(int ac, char const* const* av) if (ac >= 3) { std::vector<std::string> inputArgs; - bool hasPreset = false; - for (int i = 2; i < ac; ++i) { - if (strcmp(av[i], "--list-presets") == 0 || - cmHasLiteralPrefix(av[i], "--preset=") || - strcmp(av[i], "--preset") == 0) { - hasPreset = true; - break; - } - } - - if (hasPreset) { - inputArgs.reserve(ac - 2); - cm::append(inputArgs, av + 2, av + ac); - } else { - dir = cmSystemTools::CollapseFullPath(av[2]); - - inputArgs.reserve(ac - 3); - cm::append(inputArgs, av + 3, av + ac); - } + inputArgs.reserve(ac - 2); + cm::append(inputArgs, av + 2, av + ac); decltype(inputArgs.size()) i = 0; for (; i < inputArgs.size() && !nativeOptionsPassed; ++i) { @@ -555,6 +538,11 @@ int do_build(int ac, char const* const* av) break; } } + if (!matched && i == 0) { + dir = cmSystemTools::CollapseFullPath(arg); + matched = true; + parsed = true; + } if (!(matched && parsed)) { dir.clear(); if (!matched) { diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index 67394f9..06bceb4 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -2,11 +2,15 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmcmd.h" +#include <functional> + +#include <cm/optional> #include <cmext/algorithm> #include <cm3p/uv.h> #include <fcntl.h> +#include "cmCommandLineArgument.h" #include "cmConsoleBuf.h" #include "cmDuration.h" #include "cmGlobalGenerator.h" @@ -640,20 +644,59 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args, if (args.size() > 1) { // Copy file if (args[1] == "copy" && args.size() > 3) { + using CommandArgument = + cmCommandLineArgument<bool(const std::string& value)>; + + cm::optional<std::string> targetArg; + std::vector<CommandArgument> argParsers{ + { "-t", CommandArgument::Values::One, + CommandArgument::setToValue(targetArg) }, + }; + + std::vector<std::string> files; + for (decltype(args.size()) i = 2; i < args.size(); i++) { + const std::string& arg = args[i]; + bool matched = false; + for (auto const& m : argParsers) { + if (m.matches(arg)) { + matched = true; + if (m.parse(arg, i, args)) { + break; + } + return 1; // failed to parse + } + } + if (!matched) { + files.push_back(arg); + } + } + // If multiple source files specified, // then destination must be directory - if ((args.size() > 4) && - (!cmSystemTools::FileIsDirectory(args.back()))) { - std::cerr << "Error: Target (for copy command) \"" << args.back() + if (files.size() > 2 && !targetArg) { + targetArg = files.back(); + files.pop_back(); + } + if (targetArg && (!cmSystemTools::FileIsDirectory(*targetArg))) { + std::cerr << "Error: Target (for copy command) \"" << *targetArg << "\" is not a directory.\n"; return 1; } + if (!targetArg) { + if (files.size() < 2) { + std::cerr + << "Error: No files or target specified (for copy command).\n"; + return 1; + } + targetArg = files.back(); + files.pop_back(); + } // If error occurs we want to continue copying next files. bool return_value = false; - for (auto const& arg : cmMakeRange(args).advance(2).retreat(1)) { - if (!cmsys::SystemTools::CopyFileAlways(arg, args.back())) { - std::cerr << "Error copying file \"" << arg << "\" to \"" - << args.back() << "\".\n"; + for (auto const& file : files) { + if (!cmsys::SystemTools::CopyFileAlways(file, *targetArg)) { + std::cerr << "Error copying file \"" << file << "\" to \"" + << *targetArg << "\".\n"; return_value = true; } } diff --git a/Tests/CheckSourceTree/check.cmake b/Tests/CheckSourceTree/check.cmake index 6341bd6..655e419 100644 --- a/Tests/CheckSourceTree/check.cmake +++ b/Tests/CheckSourceTree/check.cmake @@ -4,6 +4,7 @@ if(DEFINED ENV{CTEST_REAL_HOME}) endif() file(GLOB known_files + "${CMake_SOURCE_DIR}/Tests/Java/hs_err_pid*.log" "${CMake_SOURCE_DIR}/Tests/JavaExportImport/InstallExport/hs_err_pid*.log" "${CMake_SOURCE_DIR}/Tests/JavaNativeHeaders/hs_err_pid*.log" ) diff --git a/Tests/RunCMake/CMakePresetsTest/RunCMakeTest.cmake b/Tests/RunCMake/CMakePresetsTest/RunCMakeTest.cmake index 1c7b836..5bd0158 100644 --- a/Tests/RunCMake/CMakePresetsTest/RunCMakeTest.cmake +++ b/Tests/RunCMake/CMakePresetsTest/RunCMakeTest.cmake @@ -1,5 +1,9 @@ include(RunCMake) +# Isolate our ctest runs from external environment. +unset(ENV{CTEST_PARALLEL_LEVEL}) +unset(ENV{CTEST_OUTPUT_ON_FAILURE}) + # Presets do not support legacy VS generator name architecture suffix. if(RunCMake_GENERATOR MATCHES "^(Visual Studio [0-9]+ [0-9]+) ") set(RunCMake_GENERATOR "${CMAKE_MATCH_1}") diff --git a/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake index df3e82a..8c35fe5 100644 --- a/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake +++ b/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake @@ -3,9 +3,6 @@ include(RunCTest) set(RunCMake_TEST_TIMEOUT 60) -unset(ENV{CTEST_PARALLEL_LEVEL}) -unset(ENV{CTEST_OUTPUT_ON_FAILURE}) - run_cmake_command(repeat-opt-bad1 ${CMAKE_CTEST_COMMAND} --repeat until-pass ) diff --git a/Tests/RunCMake/CommandLine/C_buildsrcdir/initial-cache.txt b/Tests/RunCMake/CommandLine/C_buildsrcdir/initial-cache.txt index adc125b..ce1cce3 100644 --- a/Tests/RunCMake/CommandLine/C_buildsrcdir/initial-cache.txt +++ b/Tests/RunCMake/CommandLine/C_buildsrcdir/initial-cache.txt @@ -1,3 +1,5 @@ +set(CMAKE_MINIMUM_REQUIRED_VERSION "" CACHE STRING "") + # Used to verify that the values match what is passed via -S and -B, and are retained in cache. set(INITIAL_SOURCE_DIR "${CMAKE_SOURCE_DIR}" CACHE PATH "defined in initial.cmake") set(INITIAL_BINARY_DIR "${CMAKE_BINARY_DIR}" CACHE PATH "defined in initial.cmake") diff --git a/Tests/RunCMake/CommandLine/E_copy-t-argument-target-is-file-result.txt b/Tests/RunCMake/CommandLine/E_copy-t-argument-target-is-file-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_copy-t-argument-target-is-file-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLine/E_copy-t-argument-target-is-file-stderr.txt b/Tests/RunCMake/CommandLine/E_copy-t-argument-target-is-file-stderr.txt new file mode 100644 index 0000000..9504216 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_copy-t-argument-target-is-file-stderr.txt @@ -0,0 +1 @@ +^Error: Target \(for copy command\).* is not a directory.$ diff --git a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake index 327b772..08c5a49 100644 --- a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake +++ b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake @@ -58,6 +58,8 @@ run_cmake_command(P_fresh ${CMAKE_COMMAND} -P "${RunCMake_SOURCE_DIR}/P_fresh.cm run_cmake_command(build-no-dir ${CMAKE_COMMAND} --build) +run_cmake_command(build-no-dir2 + ${CMAKE_COMMAND} --build --target=invalid) run_cmake_command(build-no-cache ${CMAKE_COMMAND} --build ${RunCMake_SOURCE_DIR}) run_cmake_command(build-unknown-command-short @@ -574,6 +576,12 @@ run_cmake_command(E_copy-three-source-files-target-is-file ${CMAKE_COMMAND} -E copy ${in}/f1.txt ${in}/f2.txt ${in}/f3.txt ${out}/f1.txt) run_cmake_command(E_copy-two-good-and-one-bad-source-files-target-is-directory ${CMAKE_COMMAND} -E copy ${in}/f1.txt ${in}/not_existing_file.bad ${in}/f3.txt ${out}) +run_cmake_command(E_copy-t-argument + ${CMAKE_COMMAND} -E copy ${in}/f1.txt -t ${out} ${in}/f3.txt) +run_cmake_command(E_copy-t-argument-target-is-file + ${CMAKE_COMMAND} -E copy ${in}/f1.txt -t ${out}/f1.txt ${in}/f3.txt) +run_cmake_command(E_copy-t-argument-no-source-files + ${CMAKE_COMMAND} -E copy -t ${out}) run_cmake_command(E_copy_if_different-one-source-directory-target-is-directory ${CMAKE_COMMAND} -E copy_if_different ${in}/f1.txt ${out}) run_cmake_command(E_copy_if_different-three-source-files-target-is-directory diff --git a/Tests/RunCMake/CommandLine/build-no-dir2-result.txt b/Tests/RunCMake/CommandLine/build-no-dir2-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CommandLine/build-no-dir2-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLine/build-no-dir2-stderr.txt b/Tests/RunCMake/CommandLine/build-no-dir2-stderr.txt new file mode 100644 index 0000000..4811bea --- /dev/null +++ b/Tests/RunCMake/CommandLine/build-no-dir2-stderr.txt @@ -0,0 +1 @@ +^Usage: cmake --build <dir> +\[options\] \[-- \[native-options\]\] diff --git a/Tests/RunCMake/GoogleTest/RunCMakeTest.cmake b/Tests/RunCMake/GoogleTest/RunCMakeTest.cmake index 695f562..b494cef 100644 --- a/Tests/RunCMake/GoogleTest/RunCMakeTest.cmake +++ b/Tests/RunCMake/GoogleTest/RunCMakeTest.cmake @@ -1,5 +1,9 @@ include(RunCMake) +# Isolate our ctest runs from external environment. +unset(ENV{CTEST_PARALLEL_LEVEL}) +unset(ENV{CTEST_OUTPUT_ON_FAILURE}) + if(RunCMake_GENERATOR STREQUAL "Borland Makefiles" OR RunCMake_GENERATOR STREQUAL "Watcom WMake") set(fs_delay 3) diff --git a/Tests/RunCMake/RunCTest.cmake b/Tests/RunCMake/RunCTest.cmake index 59db395..86f5b3a 100644 --- a/Tests/RunCMake/RunCTest.cmake +++ b/Tests/RunCMake/RunCTest.cmake @@ -1,5 +1,9 @@ include(RunCMake) +# Isolate our ctest runs from external environment. +unset(ENV{CTEST_PARALLEL_LEVEL}) +unset(ENV{CTEST_OUTPUT_ON_FAILURE}) + function(run_ctest CASE_NAME) configure_file(${RunCMake_SOURCE_DIR}/test.cmake.in ${RunCMake_BINARY_DIR}/${CASE_NAME}/test.cmake @ONLY) diff --git a/Tests/RunCMake/ctest_environment/RunCMakeTest.cmake b/Tests/RunCMake/ctest_environment/RunCMakeTest.cmake index 365c9e8..4716c41 100644 --- a/Tests/RunCMake/ctest_environment/RunCMakeTest.cmake +++ b/Tests/RunCMake/ctest_environment/RunCMakeTest.cmake @@ -1,9 +1,5 @@ include(RunCTest) -# Isolate our ctest runs from external environment. -unset(ENV{CTEST_PARALLEL_LEVEL}) -unset(ENV{CTEST_OUTPUT_ON_FAILURE}) - set(CASE_SOURCE_DIR "${RunCMake_SOURCE_DIR}") set(RunCTest_VERBOSE_FLAG "-VV") diff --git a/Tests/RunCMake/ctest_fixtures/RunCMakeTest.cmake b/Tests/RunCMake/ctest_fixtures/RunCMakeTest.cmake index 1754203..1c2ad89 100644 --- a/Tests/RunCMake/ctest_fixtures/RunCMakeTest.cmake +++ b/Tests/RunCMake/ctest_fixtures/RunCMakeTest.cmake @@ -1,9 +1,5 @@ include(RunCTest) -# Isolate our ctest runs from external environment. -unset(ENV{CTEST_PARALLEL_LEVEL}) -unset(ENV{CTEST_OUTPUT_ON_FAILURE}) - function(run_ctest_test CASE_NAME) set(CASE_CTEST_FIXTURES_ARGS "${ARGN}") run_ctest(${CASE_NAME}) diff --git a/Tests/RunCMake/ctest_memcheck/RunCMakeTest.cmake b/Tests/RunCMake/ctest_memcheck/RunCMakeTest.cmake index cb8f696..3f6501e 100644 --- a/Tests/RunCMake/ctest_memcheck/RunCMakeTest.cmake +++ b/Tests/RunCMake/ctest_memcheck/RunCMakeTest.cmake @@ -4,8 +4,6 @@ set(SITE test-site) set(BUILDNAME test-build) set(COVERAGE_COMMAND "") -unset(ENV{CTEST_PARALLEL_LEVEL}) - function(run_mc_test CASE_NAME CHECKER_COMMAND) run_ctest(${CASE_NAME} ${ARGN}) endfunction() diff --git a/Tests/RunCMake/ctest_test/RunCMakeTest.cmake b/Tests/RunCMake/ctest_test/RunCMakeTest.cmake index 74ae99c..242a059 100644 --- a/Tests/RunCMake/ctest_test/RunCMakeTest.cmake +++ b/Tests/RunCMake/ctest_test/RunCMakeTest.cmake @@ -1,9 +1,6 @@ include(RunCTest) set(RunCMake_TEST_TIMEOUT 60) -unset(ENV{CTEST_PARALLEL_LEVEL}) -unset(ENV{CTEST_OUTPUT_ON_FAILURE}) - set(CASE_CTEST_TEST_ARGS "") set(CASE_CTEST_TEST_LOAD "") diff --git a/Tests/RunCMake/project/CMP0048-OLD-VERSION-stderr.txt b/Tests/RunCMake/project/CMP0048-OLD-VERSION-stderr.txt index 3a13d32..c11215a 100644 --- a/Tests/RunCMake/project/CMP0048-OLD-VERSION-stderr.txt +++ b/Tests/RunCMake/project/CMP0048-OLD-VERSION-stderr.txt @@ -1,4 +1,4 @@ CMake Error at CMP0048-OLD-VERSION.cmake:1 \(project\): VERSION not allowed unless CMP0048 is set to NEW Call Stack \(most recent call first\): - CMakeLists.txt:3 \(include\)$ + CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/project/CMP0048-OLD-stderr.txt b/Tests/RunCMake/project/CMP0048-OLD-stderr.txt index 1fa70f8..695fb70 100644 --- a/Tests/RunCMake/project/CMP0048-OLD-stderr.txt +++ b/Tests/RunCMake/project/CMP0048-OLD-stderr.txt @@ -7,4 +7,4 @@ 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:3 \(include\)$ + CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/project/CMP0048-WARN-stderr.txt b/Tests/RunCMake/project/CMP0048-WARN-stderr.txt index 6d29ad2..d9be5d3 100644 --- a/Tests/RunCMake/project/CMP0048-WARN-stderr.txt +++ b/Tests/RunCMake/project/CMP0048-WARN-stderr.txt @@ -8,5 +8,5 @@ CMake Warning \(dev\) at CMP0048-WARN.cmake:3 \(project\): PROJECT_VERSION MyProject_VERSION_TWEAK Call Stack \(most recent call first\): - CMakeLists.txt:3 \(include\) + CMakeLists.txt:[0-9]+ \(include\) This warning is for project developers. Use -Wno-dev to suppress it. diff --git a/Tests/RunCMake/project/CMakeLists.txt b/Tests/RunCMake/project/CMakeLists.txt index 4b3de84..fdcaee9 100644 --- a/Tests/RunCMake/project/CMakeLists.txt +++ b/Tests/RunCMake/project/CMakeLists.txt @@ -1,3 +1,5 @@ -cmake_minimum_required(VERSION 2.8.12) +if(NOT "x${RunCMake_TEST}" STREQUAL "xNoMinimumRequired") + cmake_minimum_required(VERSION 2.8.12) +endif() project(${RunCMake_TEST} NONE) include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/project/LanguagesTwice-stderr.txt b/Tests/RunCMake/project/LanguagesTwice-stderr.txt index 9c69dd0..6edca2f 100644 --- a/Tests/RunCMake/project/LanguagesTwice-stderr.txt +++ b/Tests/RunCMake/project/LanguagesTwice-stderr.txt @@ -1,4 +1,4 @@ CMake Error at LanguagesTwice.cmake:1 \(project\): LANGUAGES may be specified at most once. Call Stack \(most recent call first\): - CMakeLists.txt:3 \(include\)$ + CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/project/NoMinimumRequired-stderr.txt b/Tests/RunCMake/project/NoMinimumRequired-stderr.txt new file mode 100644 index 0000000..83e2ac9 --- /dev/null +++ b/Tests/RunCMake/project/NoMinimumRequired-stderr.txt @@ -0,0 +1,5 @@ +CMake Warning \(dev\) at CMakeLists\.txt:[0-9]+ \(project\): + cmake_minimum_required\(\) should be called prior to this top-level project\(\) + call\. Please see the cmake-commands\(7\) manual for usage documentation of + both commands\. +This warning is for project developers\. Use -Wno-dev to suppress it\.$ diff --git a/Tests/RunCMake/project/NoMinimumRequired.cmake b/Tests/RunCMake/project/NoMinimumRequired.cmake new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/Tests/RunCMake/project/NoMinimumRequired.cmake diff --git a/Tests/RunCMake/project/RunCMakeTest.cmake b/Tests/RunCMake/project/RunCMakeTest.cmake index 6d9f52f..0f3716f 100644 --- a/Tests/RunCMake/project/RunCMakeTest.cmake +++ b/Tests/RunCMake/project/RunCMakeTest.cmake @@ -52,3 +52,5 @@ run_cmake(CMP0048-NEW) run_cmake(CMP0096-WARN) run_cmake(CMP0096-OLD) run_cmake(CMP0096-NEW) + +run_cmake(NoMinimumRequired) diff --git a/Tests/RunCMake/project/VersionInvalid-stderr.txt b/Tests/RunCMake/project/VersionInvalid-stderr.txt index 48358d1..e13a382 100644 --- a/Tests/RunCMake/project/VersionInvalid-stderr.txt +++ b/Tests/RunCMake/project/VersionInvalid-stderr.txt @@ -1,4 +1,4 @@ CMake Error at VersionInvalid.cmake:2 \(project\): VERSION "NONE" format invalid. Call Stack \(most recent call first\): - CMakeLists.txt:3 \(include\)$ + CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/project/VersionMissingLanguages-stderr.txt b/Tests/RunCMake/project/VersionMissingLanguages-stderr.txt index 576ac69..63cbf63 100644 --- a/Tests/RunCMake/project/VersionMissingLanguages-stderr.txt +++ b/Tests/RunCMake/project/VersionMissingLanguages-stderr.txt @@ -2,4 +2,4 @@ CMake Error at VersionMissingLanguages.cmake:2 \(project\): project with VERSION, DESCRIPTION or HOMEPAGE_URL must use LANGUAGES before language names. Call Stack \(most recent call first\): - CMakeLists.txt:3 \(include\)$ + CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/project/VersionTwice-stderr.txt b/Tests/RunCMake/project/VersionTwice-stderr.txt index ec07ead..dc05533 100644 --- a/Tests/RunCMake/project/VersionTwice-stderr.txt +++ b/Tests/RunCMake/project/VersionTwice-stderr.txt @@ -1,4 +1,4 @@ CMake Error at VersionTwice.cmake:2 \(project\): VERSION may be specified at most once. Call Stack \(most recent call first\): - CMakeLists.txt:3 \(include\)$ + CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/project_injected/RunCMakeTest.cmake b/Tests/RunCMake/project_injected/RunCMakeTest.cmake index ba1a003..cf63e12 100644 --- a/Tests/RunCMake/project_injected/RunCMakeTest.cmake +++ b/Tests/RunCMake/project_injected/RunCMakeTest.cmake @@ -1,6 +1,7 @@ include(RunCMake) set(RunCMake_TEST_OPTIONS + -DCMAKE_MINIMUM_REQUIRED_VERSION:STATIC= # Simulate a previous CMake run that used `project(... VERSION ...)` # in a non-injected call site. -DCMAKE_PROJECT_VERSION:STATIC=1.2.3 diff --git a/Tests/RunCMake/test_include_dirs/RunCMakeTest.cmake b/Tests/RunCMake/test_include_dirs/RunCMakeTest.cmake index 72056ae..74795c2 100644 --- a/Tests/RunCMake/test_include_dirs/RunCMakeTest.cmake +++ b/Tests/RunCMake/test_include_dirs/RunCMakeTest.cmake @@ -1,5 +1,9 @@ include(RunCMake) +# Isolate our ctest runs from external environment. +unset(ENV{CTEST_PARALLEL_LEVEL}) +unset(ENV{CTEST_OUTPUT_ON_FAILURE}) + function(run_TID) # Use a single build tree for a few tests without cleaning. set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/TID-build) diff --git a/Utilities/ClangTidyModule/CMakeLists.txt b/Utilities/ClangTidyModule/CMakeLists.txt index 8e7b2bc..c51f43a 100644 --- a/Utilities/ClangTidyModule/CMakeLists.txt +++ b/Utilities/ClangTidyModule/CMakeLists.txt @@ -14,6 +14,8 @@ find_package(Clang REQUIRED) add_library(cmake-clang-tidy-module MODULE Module.cxx + OstringstreamUseCmstrcatCheck.cxx + OstringstreamUseCmstrcatCheck.h UseBespokeEnumClassCheck.cxx UseBespokeEnumClassCheck.h UseCmstrlenCheck.cxx diff --git a/Utilities/ClangTidyModule/Module.cxx b/Utilities/ClangTidyModule/Module.cxx index ca9a812..7ef8e7d 100644 --- a/Utilities/ClangTidyModule/Module.cxx +++ b/Utilities/ClangTidyModule/Module.cxx @@ -3,6 +3,7 @@ #include <clang-tidy/ClangTidyModule.h> #include <clang-tidy/ClangTidyModuleRegistry.h> +#include "OstringstreamUseCmstrcatCheck.h" #include "UseBespokeEnumClassCheck.h" #include "UseCmstrlenCheck.h" #include "UseCmsysFstreamCheck.h" @@ -20,6 +21,8 @@ public: "cmake-use-cmsys-fstream"); CheckFactories.registerCheck<UseBespokeEnumClassCheck>( "cmake-use-bespoke-enum-class"); + CheckFactories.registerCheck<OstringstreamUseCmstrcatCheck>( + "cmake-ostringstream-use-cmstrcat"); } }; diff --git a/Utilities/ClangTidyModule/OstringstreamUseCmstrcatCheck.cxx b/Utilities/ClangTidyModule/OstringstreamUseCmstrcatCheck.cxx new file mode 100644 index 0000000..920fdf3 --- /dev/null +++ b/Utilities/ClangTidyModule/OstringstreamUseCmstrcatCheck.cxx @@ -0,0 +1,52 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "OstringstreamUseCmstrcatCheck.h" + +#include <clang/AST/Type.h> +#include <clang/ASTMatchers/ASTMatchFinder.h> + +namespace clang { +namespace tidy { +namespace cmake { +using namespace ast_matchers; + +OstringstreamUseCmstrcatCheck::OstringstreamUseCmstrcatCheck( + StringRef Name, ClangTidyContext* Context) + : ClangTidyCheck(Name, Context) +{ +} + +void OstringstreamUseCmstrcatCheck::registerMatchers(MatchFinder* Finder) +{ + Finder->addMatcher( + typeLoc(unless(elaboratedTypeLoc()), + optionally(hasParent(elaboratedTypeLoc().bind("parentType"))), + loc(qualType( + hasDeclaration(namedDecl(hasName("::std::ostringstream")))))) + .bind("ostringstream"), + this); +} + +void OstringstreamUseCmstrcatCheck::check( + const MatchFinder::MatchResult& Result) +{ + const TypeLoc* ParentTypeNode = + Result.Nodes.getNodeAs<TypeLoc>("parentType"); + const TypeLoc* RootNode = Result.Nodes.getNodeAs<TypeLoc>("ostringstream"); + + if (ParentTypeNode != nullptr) { + if (ParentTypeNode->getBeginLoc().isValid()) { + this->diag(ParentTypeNode->getBeginLoc(), + "use strings and cmStrCat() instead of std::ostringstream"); + } + + } else if (RootNode != nullptr) { + if (RootNode->getBeginLoc().isValid()) { + this->diag(RootNode->getBeginLoc(), + "use strings and cmStrCat() instead of std::ostringstream"); + } + } +} +} +} +} diff --git a/Utilities/ClangTidyModule/OstringstreamUseCmstrcatCheck.h b/Utilities/ClangTidyModule/OstringstreamUseCmstrcatCheck.h new file mode 100644 index 0000000..ecb5616 --- /dev/null +++ b/Utilities/ClangTidyModule/OstringstreamUseCmstrcatCheck.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 OstringstreamUseCmstrcatCheck : public ClangTidyCheck +{ +public: + OstringstreamUseCmstrcatCheck(StringRef Name, ClangTidyContext* Context); + void registerMatchers(ast_matchers::MatchFinder* Finder) override; + + void check(const ast_matchers::MatchFinder::MatchResult& Result) override; +}; +} +} +} diff --git a/Utilities/ClangTidyModule/Tests/CMakeLists.txt b/Utilities/ClangTidyModule/Tests/CMakeLists.txt index 2fedfa1..5bf0e89 100644 --- a/Utilities/ClangTidyModule/Tests/CMakeLists.txt +++ b/Utilities/ClangTidyModule/Tests/CMakeLists.txt @@ -13,3 +13,4 @@ endfunction() add_run_clang_tidy_test(cmake-use-cmstrlen) add_run_clang_tidy_test(cmake-use-cmsys-fstream) add_run_clang_tidy_test(cmake-use-bespoke-enum-class) +add_run_clang_tidy_test(cmake-ostringstream-use-cmstrcat) diff --git a/Utilities/ClangTidyModule/Tests/cmake-ostringstream-use-cmstrcat-stdout.txt b/Utilities/ClangTidyModule/Tests/cmake-ostringstream-use-cmstrcat-stdout.txt new file mode 100644 index 0000000..1b2d6e7 --- /dev/null +++ b/Utilities/ClangTidyModule/Tests/cmake-ostringstream-use-cmstrcat-stdout.txt @@ -0,0 +1,6 @@ +cmake-ostringstream-use-cmstrcat.cxx:5:3: warning: use strings and cmStrCat() instead of std::ostringstream [cmake-ostringstream-use-cmstrcat] + std::ostringstream test; + ^ +cmake-ostringstream-use-cmstrcat.cxx:8:13: warning: use strings and cmStrCat() instead of std::ostringstream [cmake-ostringstream-use-cmstrcat] +void check2(std::ostringstream& test2) + ^ diff --git a/Utilities/ClangTidyModule/Tests/cmake-ostringstream-use-cmstrcat.cxx b/Utilities/ClangTidyModule/Tests/cmake-ostringstream-use-cmstrcat.cxx new file mode 100644 index 0000000..ab749a6 --- /dev/null +++ b/Utilities/ClangTidyModule/Tests/cmake-ostringstream-use-cmstrcat.cxx @@ -0,0 +1,10 @@ +#include <sstream> + +void check() +{ + std::ostringstream test; +} + +void check2(std::ostringstream& test2) +{ +} |