diff options
183 files changed, 1771 insertions, 1233 deletions
diff --git a/.clang-tidy b/.clang-tidy index 7ee8bf0..9ce5f42 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,24 +1,31 @@ --- Checks: "-*,\ bugprone-*,\ +-bugprone-assignment-in-if-condition,\ -bugprone-easily-swappable-parameters,\ -bugprone-implicit-widening-of-multiplication-result,\ -bugprone-macro-parentheses,\ -bugprone-misplaced-widening-cast,\ -bugprone-narrowing-conversions,\ -bugprone-too-small-loop-variable,\ +-bugprone-unchecked-optional-access,\ misc-*,\ +-misc-confusable-identifiers,\ +-misc-const-correctness,\ -misc-no-recursion,\ -misc-non-private-member-variables-in-classes,\ -misc-static-assert,\ modernize-*,\ -modernize-avoid-c-arrays,\ +-modernize-macro-to-enum,\ -modernize-return-braced-init-list,\ +-modernize-use-emplace,\ -modernize-use-nodiscard,\ -modernize-use-noexcept,\ -modernize-use-trailing-return-type,\ -modernize-use-transparent-functors,\ performance-*,\ +-performance-inefficient-vector-operation,\ readability-*,\ -readability-convert-member-functions-to-static,\ -readability-function-cognitive-complexity,\ @@ -28,9 +35,11 @@ readability-*,\ -readability-implicit-bool-conversion,\ -readability-inconsistent-declaration-parameter-name,\ -readability-magic-numbers,\ +-readability-make-member-function-const,\ -readability-named-parameter,\ -readability-redundant-declaration,\ -readability-redundant-member-init,\ +-readability-simplify-boolean-expr,\ -readability-suspicious-call-argument,\ -readability-uppercase-literal-suffix,\ cmake-*,\ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 707756e..24e19c7 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -57,7 +57,7 @@ p:source-package: p:doc-package: extends: - - .fedora36_sphinx_package + - .fedora37_sphinx_package - .cmake_prep_doc_linux - .linux_builder_tags_qt - .cmake_doc_artifacts @@ -105,16 +105,16 @@ l:iwyu-debian10: - .linux_builder_tags - .run_automatically -l:tidy-fedora36: +l:tidy-fedora37: extends: - - .fedora36_tidy + - .fedora37_tidy - .cmake_build_linux - .linux_builder_tags_qt - .run_automatically -l:sphinx-fedora36: +l:sphinx-fedora37: extends: - - .fedora36_sphinx + - .fedora37_sphinx - .cmake_build_linux - .linux_builder_tags_qt - .run_automatically @@ -122,9 +122,9 @@ l:sphinx-fedora36: CMAKE_CI_JOB_CONTINUOUS: "true" CMAKE_CI_JOB_HELP: "true" -l:clang-analyzer-fedora36: +l:clang-analyzer-fedora37: extends: - - .fedora36_clang_analyzer + - .fedora37_clang_analyzer - .cmake_build_linux - .linux_builder_tags_qt - .run_automatically @@ -181,7 +181,7 @@ t:debian10-ninja-clang: - .debian10_ninja_clang - .cmake_test_linux_release - .linux_builder_tags_qt - - .run_manually + - .run_dependent - .needs_centos6_x86_64 variables: CMAKE_CI_JOB_NIGHTLY: "true" @@ -191,22 +191,42 @@ t:debian10-makefiles-clang: - .debian10_makefiles_clang - .cmake_test_linux_release - .linux_builder_tags_qt - - .run_manually + - .run_dependent + - .needs_centos6_x86_64 + variables: + CMAKE_CI_JOB_NIGHTLY: "true" + +t:fedora37-ninja-clang: + extends: + - .fedora37_ninja_clang + - .cmake_test_linux_release + - .linux_builder_tags_qt + - .run_dependent + - .needs_centos6_x86_64 + variables: + CMAKE_CI_JOB_NIGHTLY: "true" + +t:fedora37-makefiles-clang: + extends: + - .fedora37_makefiles_clang + - .cmake_test_linux_release + - .linux_builder_tags_qt + - .run_dependent - .needs_centos6_x86_64 variables: CMAKE_CI_JOB_NIGHTLY: "true" -t:fedora36-makefiles: +t:fedora37-makefiles: extends: - - .fedora36_makefiles + - .fedora37_makefiles - .cmake_test_linux_release - .linux_builder_tags_qt - .run_dependent - .needs_centos6_x86_64 -t:fedora36-makefiles-nospace: +t:fedora37-makefiles-nospace: extends: - - .fedora36_makefiles + - .fedora37_makefiles - .cmake_test_linux_release - .linux_builder_tags_qt - .cmake_junit_artifacts @@ -214,7 +234,7 @@ t:fedora36-makefiles-nospace: - .needs_centos6_x86_64 variables: GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake-ci" - CMAKE_CI_BUILD_NAME: fedora36_makefiles_nospace + CMAKE_CI_BUILD_NAME: fedora37_makefiles_nospace CMAKE_CI_JOB_NIGHTLY: "true" t:cuda9.2-nvidia: @@ -295,9 +315,9 @@ t:linux-gcc-cxx-modules-ninja-multi: variables: CMAKE_CI_JOB_NIGHTLY: "true" -b:fedora36-ninja: +b:fedora37-ninja: extends: - - .fedora36_ninja + - .fedora37_ninja - .cmake_build_linux - .cmake_build_artifacts - .linux_builder_tags_qt @@ -332,40 +352,40 @@ b:debian10-aarch64-extdeps: variables: CMAKE_CI_JOB_NIGHTLY: "true" -b:fedora36-extdeps: +b:fedora37-extdeps: extends: - - .fedora36_extdeps + - .fedora37_extdeps - .cmake_build_linux_standalone - .linux_builder_tags - .run_manually variables: CMAKE_CI_JOB_NIGHTLY: "true" -t:fedora36-ninja: +t:fedora37-ninja: extends: - - .fedora36_ninja + - .fedora37_ninja - .cmake_test_linux - .linux_builder_tags_x11 - .cmake_test_artifacts - .run_dependent dependencies: - - b:fedora36-ninja + - b:fedora37-ninja needs: - - b:fedora36-ninja + - b:fedora37-ninja variables: CMAKE_CI_JOB_CONTINUOUS: "true" -t:fedora36-ninja-multi: +t:fedora37-ninja-multi: extends: - - .fedora36_ninja_multi + - .fedora37_ninja_multi - .cmake_test_linux_external - .linux_builder_tags_qt - .cmake_junit_artifacts - .run_dependent dependencies: - - t:fedora36-ninja + - t:fedora37-ninja needs: - - t:fedora36-ninja + - t:fedora37-ninja t:intel2016-makefiles: extends: @@ -704,9 +724,9 @@ u:linux-aarch64-package: ## Sanitizer builds -b:fedora36-asan: +b:fedora37-asan: extends: - - .fedora36_asan + - .fedora37_asan - .cmake_build_linux - .cmake_build_artifacts - .linux_builder_tags_qt @@ -714,16 +734,16 @@ b:fedora36-asan: variables: CMAKE_CI_JOB_NIGHTLY: "true" -t:fedora36-asan: +t:fedora37-asan: extends: - - .fedora36_asan + - .fedora37_asan - .cmake_memcheck_linux - .linux_builder_tags_qt - .run_dependent dependencies: - - b:fedora36-asan + - b:fedora37-asan needs: - - b:fedora36-asan + - b:fedora37-asan variables: CMAKE_CI_JOB_NIGHTLY: "true" diff --git a/.gitlab/ci/configure_fedora36_clang_analyzer.cmake b/.gitlab/ci/configure_fedora36_clang_analyzer.cmake deleted file mode 100644 index 456936b..0000000 --- a/.gitlab/ci/configure_fedora36_clang_analyzer.cmake +++ /dev/null @@ -1 +0,0 @@ -include("${CMAKE_CURRENT_LIST_DIR}/configure_fedora36_common.cmake") diff --git a/.gitlab/ci/configure_fedora36_asan.cmake b/.gitlab/ci/configure_fedora37_asan.cmake index 51977d9..363e953 100644 --- a/.gitlab/ci/configure_fedora36_asan.cmake +++ b/.gitlab/ci/configure_fedora37_asan.cmake @@ -1,4 +1,4 @@ set(CMAKE_C_FLAGS "-fsanitize=address" CACHE STRING "") set(CMAKE_CXX_FLAGS "-fsanitize=address" CACHE STRING "") -include("${CMAKE_CURRENT_LIST_DIR}/configure_fedora36_common.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/configure_fedora37_common.cmake") diff --git a/.gitlab/ci/configure_fedora37_clang_analyzer.cmake b/.gitlab/ci/configure_fedora37_clang_analyzer.cmake new file mode 100644 index 0000000..f4c4cdd --- /dev/null +++ b/.gitlab/ci/configure_fedora37_clang_analyzer.cmake @@ -0,0 +1 @@ +include("${CMAKE_CURRENT_LIST_DIR}/configure_fedora37_common.cmake") diff --git a/.gitlab/ci/configure_fedora36_common.cmake b/.gitlab/ci/configure_fedora37_common.cmake index 4484e26..4484e26 100644 --- a/.gitlab/ci/configure_fedora36_common.cmake +++ b/.gitlab/ci/configure_fedora37_common.cmake diff --git a/.gitlab/ci/configure_fedora37_common_clang.cmake b/.gitlab/ci/configure_fedora37_common_clang.cmake new file mode 100644 index 0000000..70c9df9 --- /dev/null +++ b/.gitlab/ci/configure_fedora37_common_clang.cmake @@ -0,0 +1,6 @@ +set(CMAKE_Fortran_COMPILER "/usr/bin/flang-new" CACHE FILEPATH "") +set(CMAKE_Fortran_COMPILER_ID "LLVMFlang" CACHE STRING "") +set(CMAKE_Fortran_COMPILER_SUPPORTS_F90 "1" CACHE BOOL "") +set(CMAKE_Fortran_FLAGS "-flang-experimental-exec" CACHE STRING "") + +include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake") diff --git a/.gitlab/ci/configure_fedora36_extdeps.cmake b/.gitlab/ci/configure_fedora37_extdeps.cmake index 8e545f5..8e545f5 100644 --- a/.gitlab/ci/configure_fedora36_extdeps.cmake +++ b/.gitlab/ci/configure_fedora37_extdeps.cmake diff --git a/.gitlab/ci/configure_fedora36_makefiles.cmake b/.gitlab/ci/configure_fedora37_makefiles.cmake index 11d1a08..11d1a08 100644 --- a/.gitlab/ci/configure_fedora36_makefiles.cmake +++ b/.gitlab/ci/configure_fedora37_makefiles.cmake diff --git a/.gitlab/ci/configure_fedora37_makefiles_clang.cmake b/.gitlab/ci/configure_fedora37_makefiles_clang.cmake new file mode 100644 index 0000000..7b82a9a --- /dev/null +++ b/.gitlab/ci/configure_fedora37_makefiles_clang.cmake @@ -0,0 +1 @@ +include("${CMAKE_CURRENT_LIST_DIR}/configure_fedora37_common_clang.cmake") diff --git a/.gitlab/ci/configure_fedora36_ninja.cmake b/.gitlab/ci/configure_fedora37_ninja.cmake index 45d9192..3defa5a 100644 --- a/.gitlab/ci/configure_fedora36_ninja.cmake +++ b/.gitlab/ci/configure_fedora37_ninja.cmake @@ -10,4 +10,4 @@ set(CMAKE_CXX_FLAGS_RELEASE "-O3" CACHE STRING "") # Cover compilation with C++11 only and not higher standards. set(CMAKE_CXX_STANDARD "11" CACHE STRING "") -include("${CMAKE_CURRENT_LIST_DIR}/configure_fedora36_common.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/configure_fedora37_common.cmake") diff --git a/.gitlab/ci/configure_fedora37_ninja_clang.cmake b/.gitlab/ci/configure_fedora37_ninja_clang.cmake new file mode 100644 index 0000000..7b82a9a --- /dev/null +++ b/.gitlab/ci/configure_fedora37_ninja_clang.cmake @@ -0,0 +1 @@ +include("${CMAKE_CURRENT_LIST_DIR}/configure_fedora37_common_clang.cmake") diff --git a/.gitlab/ci/configure_fedora36_ninja_multi.cmake b/.gitlab/ci/configure_fedora37_ninja_multi.cmake index 94af721..94af721 100644 --- a/.gitlab/ci/configure_fedora36_ninja_multi.cmake +++ b/.gitlab/ci/configure_fedora37_ninja_multi.cmake diff --git a/.gitlab/ci/configure_fedora36_sphinx.cmake b/.gitlab/ci/configure_fedora37_sphinx.cmake index 90d159b..90d159b 100644 --- a/.gitlab/ci/configure_fedora36_sphinx.cmake +++ b/.gitlab/ci/configure_fedora37_sphinx.cmake diff --git a/.gitlab/ci/configure_fedora36_sphinx_package.cmake b/.gitlab/ci/configure_fedora37_sphinx_package.cmake index e839de8..e839de8 100644 --- a/.gitlab/ci/configure_fedora36_sphinx_package.cmake +++ b/.gitlab/ci/configure_fedora37_sphinx_package.cmake diff --git a/.gitlab/ci/configure_fedora36_tidy.cmake b/.gitlab/ci/configure_fedora37_tidy.cmake index 2d0eeeb..f8eb9ab 100644 --- a/.gitlab/ci/configure_fedora36_tidy.cmake +++ b/.gitlab/ci/configure_fedora37_tidy.cmake @@ -2,4 +2,4 @@ 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") +include("${CMAKE_CURRENT_LIST_DIR}/configure_fedora37_common.cmake") diff --git a/.gitlab/ci/ctest_memcheck_fedora36_asan.lsan.supp b/.gitlab/ci/ctest_memcheck_fedora37_asan.lsan.supp index 8ec1a03..8ec1a03 100644 --- a/.gitlab/ci/ctest_memcheck_fedora36_asan.lsan.supp +++ b/.gitlab/ci/ctest_memcheck_fedora37_asan.lsan.supp diff --git a/.gitlab/ci/docker/fedora36/Dockerfile b/.gitlab/ci/docker/fedora37/Dockerfile index ea42561..13ef9aa 100644 --- a/.gitlab/ci/docker/fedora36/Dockerfile +++ b/.gitlab/ci/docker/fedora37/Dockerfile @@ -1,22 +1,22 @@ -FROM fedora:36 as rvm-build +FROM fedora:37 as rvm-build MAINTAINER Ben Boeckel <ben.boeckel@kitware.com> COPY install_rvm.sh /root/install_rvm.sh RUN sh /root/install_rvm.sh -FROM fedora:36 AS clang-tidy-headers +FROM fedora:37 AS clang-tidy-headers MAINTAINER Kyle Edwards <kyle.edwards@kitware.com> COPY install_clang_tidy_headers.sh /root/install_clang_tidy_headers.sh RUN sh /root/install_clang_tidy_headers.sh -FROM fedora:36 AS iwyu +FROM fedora:37 AS iwyu MAINTAINER Kyle Edwards <kyle.edwards@kitware.com> COPY install_iwyu.sh /root/install_iwyu.sh RUN sh /root/install_iwyu.sh -FROM fedora:36 +FROM fedora:37 MAINTAINER Ben Boeckel <ben.boeckel@kitware.com> COPY install_deps.sh /root/install_deps.sh diff --git a/.gitlab/ci/docker/fedora36/install_clang_tidy_headers.sh b/.gitlab/ci/docker/fedora37/install_clang_tidy_headers.sh index b9883f4..b9883f4 100755 --- a/.gitlab/ci/docker/fedora36/install_clang_tidy_headers.sh +++ b/.gitlab/ci/docker/fedora37/install_clang_tidy_headers.sh diff --git a/.gitlab/ci/docker/fedora36/install_deps.sh b/.gitlab/ci/docker/fedora37/install_deps.sh index f117888..afb8560 100755 --- a/.gitlab/ci/docker/fedora36/install_deps.sh +++ b/.gitlab/ci/docker/fedora37/install_deps.sh @@ -11,8 +11,11 @@ dnf install --setopt=install_weak_deps=False -y \ # Install development tools. dnf install --setopt=install_weak_deps=False -y \ + clang \ clang-tools-extra \ compiler-rt \ + flang \ + flang-devel \ gcc-c++ \ git-core \ make diff --git a/.gitlab/ci/docker/fedora36/install_iwyu.sh b/.gitlab/ci/docker/fedora37/install_iwyu.sh index 714bcc0..714bcc0 100755 --- a/.gitlab/ci/docker/fedora36/install_iwyu.sh +++ b/.gitlab/ci/docker/fedora37/install_iwyu.sh diff --git a/.gitlab/ci/docker/fedora36/install_rvm.sh b/.gitlab/ci/docker/fedora37/install_rvm.sh index 0011f87..0011f87 100755 --- a/.gitlab/ci/docker/fedora36/install_rvm.sh +++ b/.gitlab/ci/docker/fedora37/install_rvm.sh diff --git a/.gitlab/ci/env_fedora36_asan.sh b/.gitlab/ci/env_fedora37_asan.sh index e976486..e976486 100644 --- a/.gitlab/ci/env_fedora36_asan.sh +++ b/.gitlab/ci/env_fedora37_asan.sh diff --git a/.gitlab/ci/env_fedora36_clang_analyzer.sh b/.gitlab/ci/env_fedora37_clang_analyzer.sh index d732c0b..d732c0b 100644 --- a/.gitlab/ci/env_fedora36_clang_analyzer.sh +++ b/.gitlab/ci/env_fedora37_clang_analyzer.sh diff --git a/.gitlab/ci/env_fedora37_common_clang.sh b/.gitlab/ci/env_fedora37_common_clang.sh new file mode 100644 index 0000000..b03b757 --- /dev/null +++ b/.gitlab/ci/env_fedora37_common_clang.sh @@ -0,0 +1,4 @@ +export CC=/usr/bin/clang-15 +export CXX=/usr/bin/clang++-15 +export FC=/usr/bin/flang-new +export FFLAGS=-flang-experimental-exec diff --git a/.gitlab/ci/env_fedora36_extdeps.sh b/.gitlab/ci/env_fedora37_extdeps.sh index 7076e18..7076e18 100644 --- a/.gitlab/ci/env_fedora36_extdeps.sh +++ b/.gitlab/ci/env_fedora37_extdeps.sh diff --git a/.gitlab/ci/env_fedora36_makefiles.cmake b/.gitlab/ci/env_fedora37_makefiles.cmake index 2bcb6d0..2bcb6d0 100644 --- a/.gitlab/ci/env_fedora36_makefiles.cmake +++ b/.gitlab/ci/env_fedora37_makefiles.cmake diff --git a/.gitlab/ci/env_fedora36_ninja_multi.sh b/.gitlab/ci/env_fedora37_makefiles.sh index 217ff30..217ff30 100644 --- a/.gitlab/ci/env_fedora36_ninja_multi.sh +++ b/.gitlab/ci/env_fedora37_makefiles.sh diff --git a/.gitlab/ci/env_fedora37_makefiles_clang.sh b/.gitlab/ci/env_fedora37_makefiles_clang.sh new file mode 100644 index 0000000..9ff1d84 --- /dev/null +++ b/.gitlab/ci/env_fedora37_makefiles_clang.sh @@ -0,0 +1 @@ +. .gitlab/ci/env_fedora37_common_clang.sh diff --git a/.gitlab/ci/env_fedora36_ninja.sh b/.gitlab/ci/env_fedora37_ninja.sh index 217ff30..217ff30 100644 --- a/.gitlab/ci/env_fedora36_ninja.sh +++ b/.gitlab/ci/env_fedora37_ninja.sh diff --git a/.gitlab/ci/env_fedora37_ninja_clang.sh b/.gitlab/ci/env_fedora37_ninja_clang.sh new file mode 100644 index 0000000..9ff1d84 --- /dev/null +++ b/.gitlab/ci/env_fedora37_ninja_clang.sh @@ -0,0 +1 @@ +. .gitlab/ci/env_fedora37_common_clang.sh diff --git a/.gitlab/ci/env_fedora36_makefiles.sh b/.gitlab/ci/env_fedora37_ninja_multi.sh index 217ff30..217ff30 100644 --- a/.gitlab/ci/env_fedora36_makefiles.sh +++ b/.gitlab/ci/env_fedora37_ninja_multi.sh diff --git a/.gitlab/ci/env_fedora36_tidy.sh b/.gitlab/ci/env_fedora37_tidy.sh index f9f08a3..f9f08a3 100644 --- a/.gitlab/ci/env_fedora36_tidy.sh +++ b/.gitlab/ci/env_fedora37_tidy.sh diff --git a/.gitlab/os-linux.yml b/.gitlab/os-linux.yml index 84950d2..8fc6ae1 100644 --- a/.gitlab/os-linux.yml +++ b/.gitlab/os-linux.yml @@ -5,7 +5,7 @@ ### Release .linux_prep_source: - image: "fedora:36" + image: "fedora:37" variables: GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci" @@ -68,8 +68,8 @@ ### Fedora -.fedora36: - image: "kitware/cmake:ci-fedora36-x86_64-2022-10-04" +.fedora37: + image: "kitware/cmake:ci-fedora37-x86_64-2022-11-16" variables: GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci/long file name for testing purposes" @@ -77,37 +77,37 @@ #### Lint builds -.fedora36_tidy: - extends: .fedora36 +.fedora37_tidy: + extends: .fedora37 variables: - CMAKE_CONFIGURATION: fedora36_tidy + CMAKE_CONFIGURATION: fedora37_tidy CTEST_NO_WARNINGS_ALLOWED: 1 CMAKE_CI_NO_INSTALL: 1 -.fedora36_clang_analyzer: - extends: .fedora36 +.fedora37_clang_analyzer: + extends: .fedora37 variables: - CMAKE_CONFIGURATION: fedora36_clang_analyzer + CMAKE_CONFIGURATION: fedora37_clang_analyzer CMAKE_CI_BUILD_TYPE: Debug CTEST_NO_WARNINGS_ALLOWED: 1 CMAKE_CI_NO_INSTALL: 1 -.fedora36_sphinx: - extends: .fedora36 +.fedora37_sphinx: + extends: .fedora37 variables: - CMAKE_CONFIGURATION: fedora36_sphinx + CMAKE_CONFIGURATION: fedora37_sphinx CTEST_NO_WARNINGS_ALLOWED: 1 CTEST_SOURCE_SUBDIRECTORY: "Utilities/Sphinx" CMAKE_CI_NO_INSTALL: 1 -.fedora36_sphinx_package: - extends: .fedora36 +.fedora37_sphinx_package: + extends: .fedora37 variables: - CMAKE_CONFIGURATION: fedora36_sphinx_package + CMAKE_CONFIGURATION: fedora37_sphinx_package CTEST_SOURCE_SUBDIRECTORY: "Utilities/Sphinx" #### Build and test @@ -153,35 +153,35 @@ CMAKE_CI_BUILD_TYPE: Release CTEST_NO_WARNINGS_ALLOWED: 1 -.fedora36_extdeps: - extends: .fedora36 +.fedora37_extdeps: + extends: .fedora37 variables: - CMAKE_CONFIGURATION: fedora36_extdeps + CMAKE_CONFIGURATION: fedora37_extdeps CMAKE_CI_BUILD_TYPE: Release CTEST_NO_WARNINGS_ALLOWED: 1 -.fedora36_ninja: - extends: .fedora36 +.fedora37_ninja: + extends: .fedora37 variables: - CMAKE_CONFIGURATION: fedora36_ninja + CMAKE_CONFIGURATION: fedora37_ninja CMAKE_CI_BUILD_TYPE: Release CTEST_NO_WARNINGS_ALLOWED: 1 -.fedora36_ninja_multi: - extends: .fedora36 +.fedora37_ninja_multi: + extends: .fedora37 variables: - CMAKE_CONFIGURATION: fedora36_ninja_multi + CMAKE_CONFIGURATION: fedora37_ninja_multi CTEST_NO_WARNINGS_ALLOWED: 1 CMAKE_GENERATOR: "Ninja Multi-Config" -.fedora36_makefiles: - extends: .fedora36 +.fedora37_makefiles: + extends: .fedora37 variables: - CMAKE_CONFIGURATION: fedora36_makefiles + CMAKE_CONFIGURATION: fedora37_makefiles CTEST_NO_WARNINGS_ALLOWED: 1 CMAKE_GENERATOR: "Unix Makefiles" @@ -200,6 +200,19 @@ variables: CMAKE_CONFIGURATION: debian10_ninja_clang +.fedora37_makefiles_clang: + extends: .fedora37 + + variables: + CMAKE_CONFIGURATION: fedora37_makefiles_clang + CMAKE_GENERATOR: "Unix Makefiles" + +.fedora37_ninja_clang: + extends: .fedora37 + + variables: + CMAKE_CONFIGURATION: fedora37_ninja_clang + ### Sanitizers .fedora_memcheck: @@ -213,13 +226,13 @@ CTEST_MEMORYCHECK_TYPE: AddressSanitizer CTEST_MEMORYCHECK_SANITIZER_OPTIONS: "" -.fedora36_asan: +.fedora37_asan: extends: - - .fedora36 + - .fedora37 - .fedora_asan_addon variables: - CMAKE_CONFIGURATION: fedora36_asan + CMAKE_CONFIGURATION: fedora37_asan ### Intel Compiler @@ -437,7 +450,7 @@ .cmake_codespell_linux: stage: build - extends: .fedora36 + extends: .fedora37 script: - codespell interruptible: true @@ -580,7 +593,7 @@ .cmake_org_help: stage: build extends: - - .fedora36 + - .fedora37 - .linux_builder_tags - .cmake_org_help_artifacts script: diff --git a/.gitlab/upload.yml b/.gitlab/upload.yml index 38d40a9..27a6ab7 100644 --- a/.gitlab/upload.yml +++ b/.gitlab/upload.yml @@ -1,7 +1,7 @@ # Steps for uploading artifacts .rsync_upload_package: - image: "fedora:36" + image: "fedora:37" stage: upload tags: - cmake @@ -21,7 +21,7 @@ .rsync_upload_help: stage: upload - image: "fedora:36" + image: "fedora:37" tags: - cmake - docker diff --git a/Help/command/file.rst b/Help/command/file.rst index 2348937..df895d0 100644 --- a/Help/command/file.rst +++ b/Help/command/file.rst @@ -750,7 +750,8 @@ The options are: file(COPY_FILE <oldname> <newname> [RESULT <result>] - [ONLY_IF_DIFFERENT]) + [ONLY_IF_DIFFERENT] + [INPUT_MAY_BE_RECENT]) .. versionadded:: 3.21 @@ -769,6 +770,14 @@ The options are: contents are already the same as ``<oldname>`` (this avoids updating ``<newname>``'s timestamp). +``INPUT_MAY_BE_RECENT`` + .. versionadded:: 3.26 + + Tell CMake that the input file may have been recently created. This is + meaningful only on Windows, where files may be inaccessible for a short + time after they are created. With this option, if permission is denied, + CMake will retry reading the input a few times. + This sub-command has some similarities to :command:`configure_file` with the ``COPYONLY`` option. An important difference is that :command:`configure_file` creates a dependency on the source file, so CMake will be re-run if it changes. diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst index faa793f..a72eac1 100644 --- a/Help/manual/cmake-generator-expressions.7.rst +++ b/Help/manual/cmake-generator-expressions.7.rst @@ -1401,6 +1401,13 @@ In the following, the phrase "the ``tgt`` filename" means the name of the Note that ``tgt`` is not added as a dependency of the target this expression is evaluated on. + .. versionchanged:: 3.26 + When encountered during evaluation of :ref:`Target Usage Requirements`, + typically in an ``INTERFACE_*`` target property, lookup of the ``tgt`` + name occurs in the directory of the target specifying the requirement, + rather than the directory of the consuming target for which the + expression is being evaluated. + .. genex:: $<TARGET_PROPERTY:prop> Value of the property ``prop`` on the target for which the expression @@ -1704,6 +1711,13 @@ Export And Install Expressions when the target is used by another target in the same buildsystem. Expands to the empty string otherwise. +.. genex:: $<BUILD_LOCAL_INTERFACE:...> + + .. versionadded:: 3.26 + + Content of ``...`` when the target is used by another target in the same + buildsystem. Expands to the empty string otherwise. + .. genex:: $<INSTALL_PREFIX> Content of the install prefix when the target is exported via diff --git a/Help/release/dev/build-local-interface-genex.rst b/Help/release/dev/build-local-interface-genex.rst new file mode 100644 index 0000000..7fe702e --- /dev/null +++ b/Help/release/dev/build-local-interface-genex.rst @@ -0,0 +1,5 @@ +build-local-interface-genex +--------------------------- + +* The :genex:`BUILD_LOCAL_INTERFACE` generator expression was added to + prevent usage requirements from being exported to dependent projects. diff --git a/Modules/CMakeDetermineFortranCompiler.cmake b/Modules/CMakeDetermineFortranCompiler.cmake index 087c0f6..d169012 100644 --- a/Modules/CMakeDetermineFortranCompiler.cmake +++ b/Modules/CMakeDetermineFortranCompiler.cmake @@ -284,6 +284,9 @@ if(MSVC_Fortran_ARCHITECTURE_ID) set(SET_MSVC_Fortran_ARCHITECTURE_ID "set(MSVC_Fortran_ARCHITECTURE_ID ${MSVC_Fortran_ARCHITECTURE_ID})") endif() +if(CMAKE_Fortran_COMPILER_ID STREQUAL "NVHPC") + set(CMAKE_Fortran_VENDOR_SOURCE_FILE_EXTENSIONS ";cuf;CUF") +endif() # configure variables set in this file for fast reload later on configure_file(${CMAKE_ROOT}/Modules/CMakeFortranCompiler.cmake.in ${CMAKE_PLATFORM_INFO_DIR}/CMakeFortranCompiler.cmake diff --git a/Modules/CMakeFortranCompiler.cmake.in b/Modules/CMakeFortranCompiler.cmake.in index 97f891e..f52ad02 100644 --- a/Modules/CMakeFortranCompiler.cmake.in +++ b/Modules/CMakeFortranCompiler.cmake.in @@ -25,7 +25,7 @@ set(CMAKE_Fortran_COMPILER_ENV_VAR "FC") set(CMAKE_Fortran_COMPILER_SUPPORTS_F90 @CMAKE_Fortran_COMPILER_SUPPORTS_F90@) set(CMAKE_Fortran_COMPILER_ID_RUN 1) -set(CMAKE_Fortran_SOURCE_FILE_EXTENSIONS f;F;fpp;FPP;f77;F77;f90;F90;for;For;FOR;f95;F95) +set(CMAKE_Fortran_SOURCE_FILE_EXTENSIONS f;F;fpp;FPP;f77;F77;f90;F90;for;For;FOR;f95;F95@CMAKE_Fortran_VENDOR_SOURCE_FILE_EXTENSIONS@) set(CMAKE_Fortran_IGNORE_EXTENSIONS h;H;o;O;obj;OBJ;def;DEF;rc;RC) set(CMAKE_Fortran_LINKER_PREFERENCE 20) if(UNIX) diff --git a/Modules/ExternalData.cmake b/Modules/ExternalData.cmake index 189374b..6826c7b 100644 --- a/Modules/ExternalData.cmake +++ b/Modules/ExternalData.cmake @@ -945,7 +945,7 @@ function(_ExternalData_link_or_copy src dst) file(CREATE_LINK "${tgt}" "${tmp}" RESULT result COPY_ON_ERROR SYMBOLIC) else() # Create a copy. - file(COPY_FILE "${src}" "${tmp}" RESULT result) + file(COPY_FILE "${src}" "${tmp}" RESULT result INPUT_MAY_BE_RECENT) endif() if(result) file(REMOVE "${tmp}") diff --git a/Modules/FindCUDAToolkit.cmake b/Modules/FindCUDAToolkit.cmake index 365b72a..62e54c8 100644 --- a/Modules/FindCUDAToolkit.cmake +++ b/Modules/FindCUDAToolkit.cmake @@ -1060,7 +1060,9 @@ if(CUDAToolkit_FOUND) if(CUDAToolkit_VERSION VERSION_GREATER_EQUAL 11.1.0) if(NOT TARGET CUDA::nvptxcompiler_static) _CUDAToolkit_find_and_add_import_lib(nvptxcompiler_static DEPS cuda_driver) - target_link_libraries(CUDA::nvptxcompiler_static INTERFACE Threads::Threads) + if(TARGET CUDA::nvptxcompiler_static) + target_link_libraries(CUDA::nvptxcompiler_static INTERFACE Threads::Threads) + endif() endif() endif() diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index c268a92..c0709c6 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -196,7 +196,6 @@ add_library( cmDependsCompiler.h cmDocumentation.cxx cmDocumentationFormatter.cxx - cmDocumentationSection.cxx cmDynamicLoader.cxx cmDynamicLoader.h cmELF.h diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 20d3508..f239c4c 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 20221117) +set(CMake_VERSION_PATCH 20221121) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) diff --git a/Source/CPack/cpack.cxx b/Source/CPack/cpack.cxx index f06946b..c228f07 100644 --- a/Source/CPack/cpack.cxx +++ b/Source/CPack/cpack.cxx @@ -5,10 +5,12 @@ #include <cstddef> #include <functional> #include <iostream> +#include <iterator> #include <map> #include <memory> #include <sstream> #include <string> +#include <type_traits> #include <utility> #include <vector> @@ -25,7 +27,6 @@ #include "cmConsoleBuf.h" #include "cmDocumentation.h" #include "cmDocumentationEntry.h" -#include "cmDocumentationFormatter.h" #include "cmGlobalGenerator.h" #include "cmMakefile.h" #include "cmState.h" @@ -36,19 +37,14 @@ #include "cmake.h" namespace { -const char* cmDocumentationName[][2] = { - { nullptr, " cpack - Packaging driver provided by CMake." }, - { nullptr, nullptr } +const cmDocumentationEntry cmDocumentationName = { + {}, + " cpack - Packaging driver provided by CMake." }; -const char* cmDocumentationUsage[][2] = { - // clang-format off - { nullptr, " cpack [options]" }, - { nullptr, nullptr } - // clang-format on -}; +const cmDocumentationEntry cmDocumentationUsage = { {}, " cpack [options]" }; -const char* cmDocumentationOptions[][2] = { +const cmDocumentationEntry cmDocumentationOptions[14] = { { "-G <generators>", "Override/define CPACK_GENERATOR" }, { "-C <Configuration>", "Specify the project configuration" }, { "-D <var>=<value>", "Set a CPack variable." }, @@ -62,14 +58,30 @@ const char* cmDocumentationOptions[][2] = { { "-B <packageDirectory>", "Override/define CPACK_PACKAGE_DIRECTORY" }, { "--vendor <vendorName>", "Override/define CPACK_PACKAGE_VENDOR" }, { "--preset", "Read arguments from a package preset" }, - { "--list-presets", "List available package presets" }, - { nullptr, nullptr } + { "--list-presets", "List available package presets" } }; void cpackProgressCallback(const std::string& message, float /*unused*/) { - std::cout << "-- " << message << std::endl; + std::cout << "-- " << message << '\n'; } + +std::vector<cmDocumentationEntry> makeGeneratorDocs( + const cmCPackGeneratorFactory& gf) +{ + const auto& generators = gf.GetGeneratorsList(); + + std::vector<cmDocumentationEntry> docs; + docs.reserve(generators.size()); + + std::transform( + generators.cbegin(), generators.cend(), std::back_inserter(docs), + [](const std::decay<decltype(generators)>::type::value_type& gen) { + return cmDocumentationEntry{ gen.first, gen.second }; + }); + return docs; +} + } // namespace // this is CPack. @@ -101,8 +113,7 @@ int main(int argc, char const* const* argv) if (cmSystemTools::GetCurrentWorkingDirectory().empty()) { cmCPack_Log(&log, cmCPackLog::LOG_ERROR, - "Current working directory cannot be established." - << std::endl); + "Current working directory cannot be established.\n"); return 1; } @@ -129,14 +140,14 @@ int main(int argc, char const* const* argv) auto const verboseLambda = [&log](const std::string&, cmake*, cmMakefile*) -> bool { log.SetVerbose(true); - cmCPack_Log(&log, cmCPackLog::LOG_OUTPUT, "Enable Verbose" << std::endl); + cmCPack_Log(&log, cmCPackLog::LOG_OUTPUT, "Enable Verbose\n"); return true; }; auto const debugLambda = [&log](const std::string&, cmake*, cmMakefile*) -> bool { log.SetDebug(true); - cmCPack_Log(&log, cmCPackLog::LOG_OUTPUT, "Enable Debug" << std::endl); + cmCPack_Log(&log, cmCPackLog::LOG_OUTPUT, "Enable Debug\n"); return true; }; @@ -194,26 +205,25 @@ int main(int argc, char const* const* argv) CommandArgument::setToValue(preset) }, CommandArgument{ "--list-presets", CommandArgument::Values::Zero, CommandArgument::setToTrue(listPresets) }, - CommandArgument{ - "-D", CommandArgument::Values::One, - [&log, &definitions](const std::string& arg, cmake*, - cmMakefile*) -> bool { - std::string value = arg; - size_t pos = value.find_first_of('='); - if (pos == std::string::npos) { - cmCPack_Log(&log, cmCPackLog::LOG_ERROR, - "Please specify CPack definitions as: KEY=VALUE" - << std::endl); - return false; - } - std::string key = value.substr(0, pos); - value.erase(0, pos + 1); - definitions[key] = value; - cmCPack_Log(&log, cmCPackLog::LOG_DEBUG, - "Set CPack variable: " << key << " to \"" << value << "\"" - << std::endl); - return true; - } }, + CommandArgument{ "-D", CommandArgument::Values::One, + [&log, &definitions](const std::string& arg, cmake*, + cmMakefile*) -> bool { + std::string value = arg; + size_t pos = value.find_first_of('='); + if (pos == std::string::npos) { + cmCPack_Log( + &log, cmCPackLog::LOG_ERROR, + "Please specify CPack definitions as: KEY=VALUE\n"); + return false; + } + std::string key = value.substr(0, pos); + value.erase(0, pos + 1); + definitions[key] = value; + cmCPack_Log(&log, cmCPackLog::LOG_DEBUG, + "Set CPack variable: " << key << " to \"" + << value << "\"\n"); + return true; + } }, }; cmake cminst(cmake::RoleScript, cmState::CPack); @@ -262,8 +272,7 @@ int main(int argc, char const* const* argv) cmCPack_Log(&log, cmCPackLog::LOG_ERROR, "Could not read presets from " << workingDirectory << ": " - << cmCMakePresetsGraph::ResultToString(result) - << std::endl); + << cmCMakePresetsGraph::ResultToString(result) << '\n'); return 1; } @@ -276,7 +285,7 @@ int main(int argc, char const* const* argv) if (presetPair == presetsGraph.PackagePresets.end()) { cmCPack_Log(&log, cmCPackLog::LOG_ERROR, "No such package preset in " << workingDirectory << ": \"" - << preset << '"' << std::endl); + << preset << "\"\n"); presetsGraph.PrintPackagePresetList(presetGeneratorsPresent); return 1; } @@ -284,8 +293,7 @@ int main(int argc, char const* const* argv) if (presetPair->second.Unexpanded.Hidden) { cmCPack_Log(&log, cmCPackLog::LOG_ERROR, "Cannot use hidden package preset in " - << workingDirectory << ": \"" << preset << '"' - << std::endl); + << workingDirectory << ": \"" << preset << "\"\n"); presetsGraph.PrintPackagePresetList(presetGeneratorsPresent); return 1; } @@ -294,7 +302,7 @@ int main(int argc, char const* const* argv) if (!expandedPreset) { cmCPack_Log(&log, cmCPackLog::LOG_ERROR, "Could not evaluate package preset \"" - << preset << "\": Invalid macro expansion" << std::endl); + << preset << "\": Invalid macro expansion\n"); presetsGraph.PrintPackagePresetList(presetGeneratorsPresent); return 1; } @@ -302,8 +310,7 @@ int main(int argc, char const* const* argv) if (!expandedPreset->ConditionResult) { cmCPack_Log(&log, cmCPackLog::LOG_ERROR, "Cannot use disabled package preset in " - << workingDirectory << ": \"" << preset << '"' - << std::endl); + << workingDirectory << ": \"" << preset << "\"\n"); presetsGraph.PrintPackagePresetList(presetGeneratorsPresent); return 1; } @@ -320,7 +327,7 @@ int main(int argc, char const* const* argv) cmCPack_Log(&log, cmCPackLog::LOG_ERROR, "No such configure preset in " << workingDirectory << ": \"" - << expandedPreset->ConfigurePreset << '"' << std::endl); + << expandedPreset->ConfigurePreset << "\"\n"); presetsGraph.PrintConfigurePresetList(); return 1; } @@ -329,7 +336,7 @@ int main(int argc, char const* const* argv) cmCPack_Log(&log, cmCPackLog::LOG_ERROR, "Cannot use hidden configure preset in " << workingDirectory << ": \"" - << expandedPreset->ConfigurePreset << '"' << std::endl); + << expandedPreset->ConfigurePreset << "\"\n"); presetsGraph.PrintConfigurePresetList(); return 1; } @@ -339,7 +346,7 @@ int main(int argc, char const* const* argv) cmCPack_Log(&log, cmCPackLog::LOG_ERROR, "Could not evaluate configure preset \"" << expandedPreset->ConfigurePreset - << "\": Invalid macro expansion" << std::endl); + << "\": Invalid macro expansion\n"); return 1; } @@ -395,7 +402,7 @@ int main(int argc, char const* const* argv) } cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE, - "Read CPack config file: " << cpackConfigFile << std::endl); + "Read CPack config file: " << cpackConfigFile << '\n'); bool cpackConfigFileSpecified = true; if (cpackConfigFile.empty()) { @@ -423,7 +430,7 @@ int main(int argc, char const* const* argv) globalMF.GetModulesFile("CMakeDetermineSystem.cmake"); if (!globalMF.ReadListFile(systemFile)) { cmCPack_Log(&log, cmCPackLog::LOG_ERROR, - "Error reading CMakeDetermineSystem.cmake" << std::endl); + "Error reading CMakeDetermineSystem.cmake\n"); return 1; } @@ -431,8 +438,7 @@ int main(int argc, char const* const* argv) globalMF.GetModulesFile("CMakeSystemSpecificInformation.cmake"); if (!globalMF.ReadListFile(systemFile)) { cmCPack_Log(&log, cmCPackLog::LOG_ERROR, - "Error reading CMakeSystemSpecificInformation.cmake" - << std::endl); + "Error reading CMakeSystemSpecificInformation.cmake\n"); return 1; } @@ -444,17 +450,17 @@ int main(int argc, char const* const* argv) cpackConfigFile = cmSystemTools::CollapseFullPath(cpackConfigFile); cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE, "Read CPack configuration file: " << cpackConfigFile - << std::endl); + << '\n'); if (!globalMF.ReadListFile(cpackConfigFile)) { cmCPack_Log(&log, cmCPackLog::LOG_ERROR, - "Problem reading CPack config file: \"" - << cpackConfigFile << "\"" << std::endl); + "Problem reading CPack config file: \"" << cpackConfigFile + << "\"\n"); return 1; } } else if (cpackConfigFileSpecified) { cmCPack_Log(&log, cmCPackLog::LOG_ERROR, "Cannot find CPack config file: \"" << cpackConfigFile - << "\"" << std::endl); + << "\"\n"); return 1; } @@ -503,17 +509,17 @@ int main(int argc, char const* const* argv) cmValue genList = globalMF.GetDefinition("CPACK_GENERATOR"); if (!genList) { cmCPack_Log(&log, cmCPackLog::LOG_ERROR, - "CPack generator not specified" << std::endl); + "CPack generator not specified\n"); } else { std::vector<std::string> generatorsVector = cmExpandedList(*genList); for (std::string const& gen : generatorsVector) { cmMakefile::ScopePushPop raii(&globalMF); cmMakefile* mf = &globalMF; cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE, - "Specified generator: " << gen << std::endl); + "Specified generator: " << gen << '\n'); if (!mf->GetDefinition("CPACK_PACKAGE_NAME")) { cmCPack_Log(&log, cmCPackLog::LOG_ERROR, - "CPack project name not specified" << std::endl); + "CPack project name not specified" << '\n'); parsed = false; } if (parsed && @@ -522,13 +528,11 @@ int main(int argc, char const* const* argv) mf->GetDefinition("CPACK_PACKAGE_VERSION_MINOR") && mf->GetDefinition("CPACK_PACKAGE_VERSION_PATCH")))) { cmCPack_Log(&log, cmCPackLog::LOG_ERROR, - "CPack project version not specified" - << std::endl - << "Specify CPACK_PACKAGE_VERSION, or " - "CPACK_PACKAGE_VERSION_MAJOR, " - "CPACK_PACKAGE_VERSION_MINOR, and " - "CPACK_PACKAGE_VERSION_PATCH." - << std::endl); + "CPack project version not specified\n" + "Specify CPACK_PACKAGE_VERSION, or " + "CPACK_PACKAGE_VERSION_MAJOR, " + "CPACK_PACKAGE_VERSION_MINOR, and " + "CPACK_PACKAGE_VERSION_PATCH.\n"); parsed = false; } if (parsed) { @@ -539,19 +543,12 @@ int main(int argc, char const* const* argv) cpackGenerator->SetTraceExpand(cminst.GetTraceExpand()); } else { cmCPack_Log(&log, cmCPackLog::LOG_ERROR, - "Could not create CPack generator: " << gen - << std::endl); + "Could not create CPack generator: " << gen << '\n'); // Print out all the valid generators cmDocumentation generatorDocs; - std::vector<cmDocumentationEntry> v; - for (auto const& g : generators.GetGeneratorsList()) { - cmDocumentationEntry e; - e.Name = g.first; - e.Brief = g.second; - v.push_back(std::move(e)); - } - generatorDocs.SetSection("Generators", v); - std::cerr << "\n"; + generatorDocs.SetSection("Generators", + makeGeneratorDocs(generators)); + std::cerr << '\n'; generatorDocs.PrintDocumentation(cmDocumentation::ListGenerators, std::cerr); parsed = false; @@ -559,8 +556,7 @@ int main(int argc, char const* const* argv) if (parsed && !cpackGenerator->Initialize(gen, mf)) { cmCPack_Log(&log, cmCPackLog::LOG_ERROR, - "Cannot initialize the generator " << gen - << std::endl); + "Cannot initialize the generator " << gen << '\n'); parsed = false; } @@ -573,17 +569,16 @@ int main(int argc, char const* const* argv) "Please specify build tree of the project that uses CMake " "using CPACK_INSTALL_CMAKE_PROJECTS, specify " "CPACK_INSTALL_COMMANDS, CPACK_INSTALL_SCRIPT, or " - "CPACK_INSTALLED_DIRECTORIES." - << std::endl); + "CPACK_INSTALLED_DIRECTORIES.\n"); parsed = false; } if (parsed) { cmValue projName = mf->GetDefinition("CPACK_PACKAGE_NAME"); cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE, "Use generator: " << cpackGenerator->GetNameOfClass() - << std::endl); + << '\n'); cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE, - "For project: " << *projName << std::endl); + "For project: " << *projName << '\n'); cmValue projVersion = mf->GetDefinition("CPACK_PACKAGE_VERSION"); if (!projVersion) { @@ -594,7 +589,7 @@ int main(int argc, char const* const* argv) cmValue projVersionPatch = mf->GetDefinition("CPACK_PACKAGE_VERSION_PATCH"); std::ostringstream ostr; - ostr << *projVersionMajor << "." << *projVersionMinor << "." + ostr << *projVersionMajor << "." << *projVersionMinor << '.' << *projVersionPatch; mf->AddDefinition("CPACK_PACKAGE_VERSION", ostr.str()); } @@ -603,7 +598,7 @@ int main(int argc, char const* const* argv) if (!res) { cmCPack_Log(&log, cmCPackLog::LOG_ERROR, "Error when generating package: " << *projName - << std::endl); + << '\n'); return 1; } } @@ -618,27 +613,13 @@ int main(int argc, char const* const* argv) */ if (help) { // Construct and print requested documentation. - doc.SetName("cpack"); doc.SetSection("Name", cmDocumentationName); doc.SetSection("Usage", cmDocumentationUsage); doc.PrependSection("Options", cmDocumentationOptions); - - std::vector<cmDocumentationEntry> v; - for (auto const& g : generators.GetGeneratorsList()) { - cmDocumentationEntry e; - e.Name = g.first; - e.Brief = g.second; - v.push_back(std::move(e)); - } - doc.SetSection("Generators", v); - - return doc.PrintRequestedDocumentation(std::cout) ? 0 : 1; - } - - if (cmSystemTools::GetErrorOccurredFlag()) { - return 1; + doc.SetSection("Generators", makeGeneratorDocs(generators)); + return !doc.PrintRequestedDocumentation(std::cout); } - return 0; + return int(cmSystemTools::GetErrorOccurredFlag()); } diff --git a/Source/CursesDialog/ccmake.cxx b/Source/CursesDialog/ccmake.cxx index 70ed648..18c1a80 100644 --- a/Source/CursesDialog/ccmake.cxx +++ b/Source/CursesDialog/ccmake.cxx @@ -16,45 +16,38 @@ #include "cmCursesMainForm.h" #include "cmCursesStandardIncludes.h" #include "cmDocumentation.h" -#include "cmDocumentationEntry.h" // IWYU pragma: keep +#include "cmDocumentationEntry.h" #include "cmMessageMetadata.h" #include "cmState.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmake.h" -static const char* cmDocumentationName[][2] = { - { nullptr, " ccmake - Curses Interface for CMake." }, - { nullptr, nullptr } +namespace { +const cmDocumentationEntry cmDocumentationName = { + {}, + " ccmake - Curses Interface for CMake." }; -static const char* cmDocumentationUsage[][2] = { - { nullptr, +const cmDocumentationEntry cmDocumentationUsage[2] = { + { {}, " ccmake <path-to-source>\n" " ccmake <path-to-existing-build>" }, - { nullptr, + { {}, "Specify a source directory to (re-)generate a build system for " "it in the current working directory. Specify an existing build " "directory to re-generate its build system." }, - { nullptr, nullptr } }; -static const char* cmDocumentationUsageNote[][2] = { - { nullptr, "Run 'ccmake --help' for more information." }, - { nullptr, nullptr } +const cmDocumentationEntry cmDocumentationUsageNote = { + {}, + "Run 'ccmake --help' for more information." }; -static const char* cmDocumentationOptions[][2] = { - CMAKE_STANDARD_OPTIONS_TABLE, - { nullptr, nullptr } -}; - -cmCursesForm* cmCursesForm::CurrentForm = nullptr; - #ifndef _WIN32 extern "C" { -static void onsig(int /*unused*/) +void onsig(int /*unused*/) { if (cmCursesForm::CurrentForm) { cmCursesForm::CurrentForm->HandleResize(); @@ -63,6 +56,9 @@ static void onsig(int /*unused*/) } } #endif // _WIN32 +} // anonymous namespace + +cmCursesForm* cmCursesForm::CurrentForm = nullptr; int main(int argc, char const* const* argv) { @@ -89,8 +85,8 @@ int main(int argc, char const* const* argv) doc.AppendSection("Usage", cmDocumentationUsageNote); } doc.AppendSection("Generators", generators); - doc.PrependSection("Options", cmDocumentationOptions); - return doc.PrintRequestedDocumentation(std::cout) ? 0 : 1; + doc.PrependSection("Options", cmake::CMAKE_STANDARD_OPTIONS_TABLE); + return !doc.PrintRequestedDocumentation(std::cout); } bool debug = false; diff --git a/Source/QtDialog/CMakeSetup.cxx b/Source/QtDialog/CMakeSetup.cxx index 591b793..50e8e3a 100644 --- a/Source/QtDialog/CMakeSetup.cxx +++ b/Source/QtDialog/CMakeSetup.cxx @@ -22,26 +22,27 @@ #include "cmSystemTools.h" // IWYU pragma: keep #include "cmake.h" -static const char* cmDocumentationName[][2] = { { nullptr, - " cmake-gui - CMake GUI." }, - { nullptr, nullptr } }; - -static const char* cmDocumentationUsage[][2] = { - { nullptr, - " cmake-gui [options]\n" - " cmake-gui [options] <path-to-source>\n" - " cmake-gui [options] <path-to-existing-build>\n" - " cmake-gui [options] -S <path-to-source> -B <path-to-build>\n" - " cmake-gui [options] --browse-manual\n" }, - { nullptr, nullptr } +namespace { +const cmDocumentationEntry cmDocumentationName = { + {}, + " cmake-gui - CMake GUI." }; -static const char* cmDocumentationOptions[][2] = { +const cmDocumentationEntry cmDocumentationUsage = { + {}, + " cmake-gui [options]\n" + " cmake-gui [options] <path-to-source>\n" + " cmake-gui [options] <path-to-existing-build>\n" + " cmake-gui [options] -S <path-to-source> -B <path-to-build>\n" + " cmake-gui [options] --browse-manual" +}; + +const cmDocumentationEntry cmDocumentationOptions[3] = { { "-S <path-to-source>", "Explicitly specify a source directory." }, { "-B <path-to-build>", "Explicitly specify a build directory." }, - { "--preset=<preset>", "Specify a configure preset." }, - { nullptr, nullptr } + { "--preset=<preset>", "Specify a configure preset." } }; +} // anonymous namespace #if defined(Q_OS_MAC) static int cmOSXInstall(std::string dir); @@ -91,7 +92,7 @@ int main(int argc, char** argv) doc.AppendSection("Generators", generators); doc.PrependSection("Options", cmDocumentationOptions); - return (doc.PrintRequestedDocumentation(std::cout) ? 0 : 1); + return !doc.PrintRequestedDocumentation(std::cout); } #if defined(Q_OS_MAC) @@ -252,6 +253,7 @@ int main(int argc, char** argv) # include <unistd.h> # include "cm_sys_stat.h" + static bool cmOSXInstall(std::string const& dir, std::string const& tool) { if (tool.empty()) { @@ -277,6 +279,7 @@ static bool cmOSXInstall(std::string const& dir, std::string const& tool) << "': " << strerror(err) << "\n"; return false; } + static int cmOSXInstall(std::string dir) { if (!cmHasLiteralSuffix(dir, "/")) { diff --git a/Source/cmCMakePresetsGraphInternal.h b/Source/cmCMakePresetsGraphInternal.h index 9e47a69..2726e92 100644 --- a/Source/cmCMakePresetsGraphInternal.h +++ b/Source/cmCMakePresetsGraphInternal.h @@ -1,5 +1,7 @@ /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + #include <memory> #include <string> #include <vector> diff --git a/Source/cmCPluginAPI.h b/Source/cmCPluginAPI.h index 19626f0..0d8a366 100644 --- a/Source/cmCPluginAPI.h +++ b/Source/cmCPluginAPI.h @@ -8,7 +8,7 @@ loosely into four groups 1) Utility 2) cmMakefile 3) cmSourceFile 4) cmSystemTools. Within each grouping functions are listed alphabetically */ /*=========================================================================*/ -#ifndef cmCPluginAPI_h +#ifndef cmCPluginAPI_h /* NOLINT(cmake-use-pragma-once) */ #define cmCPluginAPI_h #define CMAKE_VERSION_MAJOR 2 diff --git a/Source/cmDocumentation.cxx b/Source/cmDocumentation.cxx index d466a12..77c5295 100644 --- a/Source/cmDocumentation.cxx +++ b/Source/cmDocumentation.cxx @@ -16,7 +16,8 @@ #include "cmSystemTools.h" #include "cmVersion.h" -static const char* cmDocumentationStandardOptions[][2] = { +namespace { +const cmDocumentationEntry cmDocumentationStandardOptions[20] = { { "-h,-H,--help,-help,-usage,/?", "Print usage information and exit." }, { "--version,-version,/V [<file>]", "Print version number and exit." }, { "--help-full [<file>]", "Print all help manuals and exit." }, @@ -42,22 +43,27 @@ static const char* cmDocumentationStandardOptions[][2] = { { "--help-variable var [<file>]", "Print help for one variable and exit." }, { "--help-variable-list [<file>]", "List variables with help available and exit." }, - { "--help-variables [<file>]", "Print cmake-variables manual and exit." }, - { nullptr, nullptr } + { "--help-variables [<file>]", "Print cmake-variables manual and exit." } }; -static const char* cmDocumentationCPackGeneratorsHeader[][2] = { - { nullptr, "The following generators are available on this platform:" }, - { nullptr, nullptr } +const cmDocumentationEntry cmDocumentationCPackGeneratorsHeader = { + {}, + "The following generators are available on this platform:" }; -static const char* cmDocumentationCMakeGeneratorsHeader[][2] = { - { nullptr, - "The following generators are available on this platform (* marks " - "default):" }, - { nullptr, nullptr } +const cmDocumentationEntry cmDocumentationCMakeGeneratorsHeader = { + {}, + "The following generators are available on this platform (* marks " + "default):" }; +bool isOption(const char* arg) +{ + return ((arg[0] == '-') || (strcmp(arg, "/V") == 0) || + (strcmp(arg, "/?") == 0)); +} +} // anonymous namespace + cmDocumentation::cmDocumentation() { this->addCommonStandardDocSections(); @@ -148,14 +154,6 @@ bool cmDocumentation::PrintRequestedDocumentation(std::ostream& os) return result; } -#define GET_OPT_ARGUMENT(target) \ - do { \ - if ((i + 1 < argc) && !this->IsOption(argv[i + 1])) { \ - (target) = argv[i + 1]; \ - i = i + 1; \ - }; \ - } while (false) - void cmDocumentation::WarnFormFromFilename( cmDocumentation::RequestedHelpItem& request, bool& result) { @@ -217,6 +215,14 @@ bool cmDocumentation::CheckOptions(int argc, const char* const* argv, return true; } + auto get_opt_argument = [=](const int nextIdx, std::string& target) -> bool { + if ((nextIdx < argc) && !isOption(argv[nextIdx])) { + target = argv[nextIdx]; + return true; + } + return false; + }; + // Search for supported help options. bool result = false; @@ -230,7 +236,7 @@ bool cmDocumentation::CheckOptions(int argc, const char* const* argv, (strcmp(argv[i], "/?") == 0) || (strcmp(argv[i], "-usage") == 0) || (strcmp(argv[i], "-h") == 0) || (strcmp(argv[i], "-H") == 0)) { help.HelpType = cmDocumentation::Help; - GET_OPT_ARGUMENT(help.Argument); + i += int(get_opt_argument(i + 1, help.Argument)); help.Argument = cmSystemTools::LowerCase(help.Argument); // special case for single command if (!help.Argument.empty()) { @@ -239,25 +245,25 @@ bool cmDocumentation::CheckOptions(int argc, const char* const* argv, } else if (strcmp(argv[i], "--help-properties") == 0) { help.HelpType = cmDocumentation::OneManual; help.Argument = "cmake-properties.7"; - GET_OPT_ARGUMENT(help.Filename); + i += int(get_opt_argument(i + 1, help.Filename)); this->WarnFormFromFilename(help, result); } else if (strcmp(argv[i], "--help-policies") == 0) { help.HelpType = cmDocumentation::OneManual; help.Argument = "cmake-policies.7"; - GET_OPT_ARGUMENT(help.Filename); + i += int(get_opt_argument(i + 1, help.Filename)); this->WarnFormFromFilename(help, result); } else if (strcmp(argv[i], "--help-variables") == 0) { help.HelpType = cmDocumentation::OneManual; help.Argument = "cmake-variables.7"; - GET_OPT_ARGUMENT(help.Filename); + i += int(get_opt_argument(i + 1, help.Filename)); this->WarnFormFromFilename(help, result); } else if (strcmp(argv[i], "--help-modules") == 0) { help.HelpType = cmDocumentation::OneManual; help.Argument = "cmake-modules.7"; - GET_OPT_ARGUMENT(help.Filename); + i += int(get_opt_argument(i + 1, help.Filename)); this->WarnFormFromFilename(help, result); } else if (strcmp(argv[i], "--help-custom-modules") == 0) { - GET_OPT_ARGUMENT(help.Filename); + i += int(get_opt_argument(i + 1, help.Filename)); cmSystemTools::Message( "Warning: --help-custom-modules no longer supported"); if (help.Filename.empty()) { @@ -271,83 +277,79 @@ bool cmDocumentation::CheckOptions(int argc, const char* const* argv, } else if (strcmp(argv[i], "--help-commands") == 0) { help.HelpType = cmDocumentation::OneManual; help.Argument = "cmake-commands.7"; - GET_OPT_ARGUMENT(help.Filename); + i += int(get_opt_argument(i + 1, help.Filename)); this->WarnFormFromFilename(help, result); } else if (strcmp(argv[i], "--help-compatcommands") == 0) { - GET_OPT_ARGUMENT(help.Filename); cmSystemTools::Message( "Warning: --help-compatcommands no longer supported"); return true; } else if (strcmp(argv[i], "--help-full") == 0) { help.HelpType = cmDocumentation::Full; - GET_OPT_ARGUMENT(help.Filename); + i += int(get_opt_argument(i + 1, help.Filename)); this->WarnFormFromFilename(help, result); } else if (strcmp(argv[i], "--help-html") == 0) { - GET_OPT_ARGUMENT(help.Filename); cmSystemTools::Message("Warning: --help-html no longer supported"); return true; } else if (strcmp(argv[i], "--help-man") == 0) { - GET_OPT_ARGUMENT(help.Filename); cmSystemTools::Message("Warning: --help-man no longer supported"); return true; } else if (strcmp(argv[i], "--help-command") == 0) { help.HelpType = cmDocumentation::OneCommand; - GET_OPT_ARGUMENT(help.Argument); - GET_OPT_ARGUMENT(help.Filename); + i += int(get_opt_argument(i + 1, help.Argument)); + i += int(get_opt_argument(i + 1, help.Filename)); help.Argument = cmSystemTools::LowerCase(help.Argument); this->WarnFormFromFilename(help, result); } else if (strcmp(argv[i], "--help-module") == 0) { help.HelpType = cmDocumentation::OneModule; - GET_OPT_ARGUMENT(help.Argument); - GET_OPT_ARGUMENT(help.Filename); + i += int(get_opt_argument(i + 1, help.Argument)); + i += int(get_opt_argument(i + 1, help.Filename)); this->WarnFormFromFilename(help, result); } else if (strcmp(argv[i], "--help-property") == 0) { help.HelpType = cmDocumentation::OneProperty; - GET_OPT_ARGUMENT(help.Argument); - GET_OPT_ARGUMENT(help.Filename); + i += int(get_opt_argument(i + 1, help.Argument)); + i += int(get_opt_argument(i + 1, help.Filename)); this->WarnFormFromFilename(help, result); } else if (strcmp(argv[i], "--help-policy") == 0) { help.HelpType = cmDocumentation::OnePolicy; - GET_OPT_ARGUMENT(help.Argument); - GET_OPT_ARGUMENT(help.Filename); + i += int(get_opt_argument(i + 1, help.Argument)); + i += int(get_opt_argument(i + 1, help.Filename)); this->WarnFormFromFilename(help, result); } else if (strcmp(argv[i], "--help-variable") == 0) { help.HelpType = cmDocumentation::OneVariable; - GET_OPT_ARGUMENT(help.Argument); - GET_OPT_ARGUMENT(help.Filename); + i += int(get_opt_argument(i + 1, help.Argument)); + i += int(get_opt_argument(i + 1, help.Filename)); this->WarnFormFromFilename(help, result); } else if (strcmp(argv[i], "--help-manual") == 0) { help.HelpType = cmDocumentation::OneManual; - GET_OPT_ARGUMENT(help.Argument); - GET_OPT_ARGUMENT(help.Filename); + i += int(get_opt_argument(i + 1, help.Argument)); + i += int(get_opt_argument(i + 1, help.Filename)); this->WarnFormFromFilename(help, result); } else if (strcmp(argv[i], "--help-command-list") == 0) { help.HelpType = cmDocumentation::ListCommands; - GET_OPT_ARGUMENT(help.Filename); + i += int(get_opt_argument(i + 1, help.Filename)); } else if (strcmp(argv[i], "--help-module-list") == 0) { help.HelpType = cmDocumentation::ListModules; - GET_OPT_ARGUMENT(help.Filename); + i += int(get_opt_argument(i + 1, help.Filename)); } else if (strcmp(argv[i], "--help-property-list") == 0) { help.HelpType = cmDocumentation::ListProperties; - GET_OPT_ARGUMENT(help.Filename); + i += int(get_opt_argument(i + 1, help.Filename)); } else if (strcmp(argv[i], "--help-variable-list") == 0) { help.HelpType = cmDocumentation::ListVariables; - GET_OPT_ARGUMENT(help.Filename); + i += int(get_opt_argument(i + 1, help.Filename)); } else if (strcmp(argv[i], "--help-policy-list") == 0) { help.HelpType = cmDocumentation::ListPolicies; - GET_OPT_ARGUMENT(help.Filename); + i += int(get_opt_argument(i + 1, help.Filename)); } else if (strcmp(argv[i], "--help-manual-list") == 0) { help.HelpType = cmDocumentation::ListManuals; - GET_OPT_ARGUMENT(help.Filename); + i += int(get_opt_argument(i + 1, help.Filename)); } else if (strcmp(argv[i], "--copyright") == 0) { - GET_OPT_ARGUMENT(help.Filename); cmSystemTools::Message("Warning: --copyright no longer supported"); return true; } else if ((strcmp(argv[i], "--version") == 0) || (strcmp(argv[i], "-version") == 0) || (strcmp(argv[i], "/V") == 0)) { help.HelpType = cmDocumentation::Version; - GET_OPT_ARGUMENT(help.Filename); + i += int(get_opt_argument(i + 1, help.Filename)); } if (help.HelpType != None) { // This is a help option. See if there is a file name given. @@ -369,56 +371,12 @@ void cmDocumentation::SetSection(const char* name, this->SectionAtName(name) = std::move(section); } -void cmDocumentation::SetSection(const char* name, - std::vector<cmDocumentationEntry>& docs) -{ - cmDocumentationSection sec{ name }; - sec.Append(docs); - this->SetSection(name, std::move(sec)); -} - -void cmDocumentation::SetSection(const char* name, const char* docs[][2]) -{ - cmDocumentationSection sec{ name }; - sec.Append(docs); - this->SetSection(name, std::move(sec)); -} - -void cmDocumentation::SetSections( - std::map<std::string, cmDocumentationSection> sections) -{ - for (auto& s : sections) { - this->SetSection(s.first.c_str(), std::move(s.second)); - } -} cmDocumentationSection& cmDocumentation::SectionAtName(const char* name) { return this->AllSections.emplace(name, cmDocumentationSection{ name }) .first->second; } -void cmDocumentation::PrependSection(const char* name, const char* docs[][2]) -{ - this->SectionAtName(name).Prepend(docs); -} - -void cmDocumentation::PrependSection(const char* name, - std::vector<cmDocumentationEntry>& docs) -{ - this->SectionAtName(name).Prepend(docs); -} - -void cmDocumentation::AppendSection(const char* name, const char* docs[][2]) -{ - this->SectionAtName(name).Append(docs); -} - -void cmDocumentation::AppendSection(const char* name, - std::vector<cmDocumentationEntry>& docs) -{ - this->SectionAtName(name).Append(docs); -} - void cmDocumentation::AppendSection(const char* name, cmDocumentationEntry& docs) { @@ -465,7 +423,7 @@ void cmDocumentation::PrintNames(std::ostream& os, std::string const& pattern) } std::sort(names.begin(), names.end()); for (std::string const& n : names) { - os << n << "\n"; + os << n << '\n'; } } @@ -501,7 +459,7 @@ bool cmDocumentation::PrintHelpOneManual(std::ostream& os) // Argument was not a manual. Complain. os << "Argument \"" << this->CurrentArgument << "\" to --help-manual is not an available manual. " - << "Use --help-manual-list to see all available manuals.\n"; + "Use --help-manual-list to see all available manuals.\n"; return false; } @@ -520,7 +478,7 @@ bool cmDocumentation::PrintHelpOneCommand(std::ostream& os) // Argument was not a command. Complain. os << "Argument \"" << this->CurrentArgument << "\" to --help-command is not a CMake command. " - << "Use --help-command-list to see all commands.\n"; + "Use --help-command-list to see all commands.\n"; return false; } @@ -553,7 +511,7 @@ bool cmDocumentation::PrintHelpListModules(std::ostream& os) } std::sort(modules.begin(), modules.end()); for (std::string const& m : modules) { - os << m << "\n"; + os << m << '\n'; } return true; } @@ -567,7 +525,7 @@ bool cmDocumentation::PrintHelpOneProperty(std::ostream& os) // Argument was not a property. Complain. os << "Argument \"" << this->CurrentArgument << "\" to --help-property is not a CMake property. " - << "Use --help-property-list to see all properties.\n"; + "Use --help-property-list to see all properties.\n"; return false; } @@ -601,7 +559,6 @@ bool cmDocumentation::PrintHelpListGenerators(std::ostream& os) { const auto si = this->AllSections.find("Generators"); if (si != this->AllSections.end()) { - this->Formatter.SetIndent(" "); this->Formatter.PrintSection(os, si->second); } return true; @@ -616,7 +573,7 @@ bool cmDocumentation::PrintHelpOneVariable(std::ostream& os) // Argument was not a variable. Complain. os << "Argument \"" << this->CurrentArgument << "\" to --help-variable is not a defined variable. " - << "Use --help-variable-list to see all defined variables.\n"; + "Use --help-variable-list to see all defined variables.\n"; return false; } @@ -662,12 +619,6 @@ const char* cmDocumentation::GetNameString() const return "CMake"; } -bool cmDocumentation::IsOption(const char* arg) const -{ - return ((arg[0] == '-') || (strcmp(arg, "/V") == 0) || - (strcmp(arg, "/?") == 0)); -} - bool cmDocumentation::PrintOldCustomModules(std::ostream& os) { // CheckOptions abuses the Argument field to give us the file name. @@ -691,7 +642,7 @@ bool cmDocumentation::PrintOldCustomModules(std::ostream& os) } else if ((ext.length() == 2) && (ext[1] >= '1') && (ext[1] <= '9')) { /* clang-format off */ os << - ".TH " << name << " " << ext[1] << " \"" << + ".TH " << name << ' ' << ext[1] << " \"" << cmSystemTools::GetCurrentDateTime("%B %d, %Y") << "\" \"cmake " << cmVersion::GetCMakeVersion() << "\"\n" ".SH NAME\n" @@ -704,7 +655,7 @@ bool cmDocumentation::PrintOldCustomModules(std::ostream& os) ; /* clang-format on */ } else { - os << name << "\n\n" << summary << "\n" << detail; + os << name << "\n\n" << summary << '\n' << detail; } return true; } diff --git a/Source/cmDocumentation.h b/Source/cmDocumentation.h index 313be32..6930986 100644 --- a/Source/cmDocumentation.h +++ b/Source/cmDocumentation.h @@ -7,6 +7,7 @@ #include <iosfwd> #include <map> #include <string> +#include <utility> #include <vector> #include "cmDocumentationFormatter.h" @@ -15,9 +16,33 @@ struct cmDocumentationEntry; /** Class to generate documentation. */ -class cmDocumentation : public cmDocumentationEnums +class cmDocumentation { public: + /** Types of help provided. */ + enum Type + { + None, + Version, + Usage, + Help, + Full, + ListManuals, + ListCommands, + ListModules, + ListProperties, + ListVariables, + ListPolicies, + ListGenerators, + OneManual, + OneCommand, + OneModule, + OneProperty, + OneVariable, + OnePolicy, + OldCustomModules + }; + cmDocumentation(); /** @@ -50,19 +75,26 @@ public: /** Set a section of the documentation. Typical sections include Name, Usage, Description, Options */ void SetSection(const char* sectionName, cmDocumentationSection section); - void SetSection(const char* sectionName, - std::vector<cmDocumentationEntry>& docs); - void SetSection(const char* sectionName, const char* docs[][2]); - void SetSections(std::map<std::string, cmDocumentationSection> sections); + template <typename Iterable> + void SetSection(const char* sectionName, const Iterable& docs) + { + cmDocumentationSection sec{ sectionName }; + sec.Append(docs); + this->SetSection(sectionName, std::move(sec)); + } /** Add the documentation to the beginning/end of the section */ - void PrependSection(const char* sectionName, const char* docs[][2]); - void PrependSection(const char* sectionName, - std::vector<cmDocumentationEntry>& docs); + template <typename Iterable> + void PrependSection(const char* sectionName, const Iterable& docs) + { + this->SectionAtName(sectionName).Prepend(docs); + } void PrependSection(const char* sectionName, cmDocumentationEntry& docs); - void AppendSection(const char* sectionName, const char* docs[][2]); - void AppendSection(const char* sectionName, - std::vector<cmDocumentationEntry>& docs); + template <typename Iterable> + void AppendSection(const char* sectionName, const Iterable& docs) + { + this->SectionAtName(sectionName).Append(docs); + } void AppendSection(const char* sectionName, cmDocumentationEntry& docs); /** Add common (to all tools) documentation section(s) */ @@ -102,7 +134,6 @@ private: bool PrintOldCustomModules(std::ostream& os); const char* GetNameString() const; - bool IsOption(const char* arg) const; bool ShowGenerators; @@ -114,7 +145,7 @@ private: struct RequestedHelpItem { - cmDocumentationEnums::Type HelpType = None; + Type HelpType = None; std::string Filename; std::string Argument; }; diff --git a/Source/cmDocumentationEntry.h b/Source/cmDocumentationEntry.h index 89a2899..d971836 100644 --- a/Source/cmDocumentationEntry.h +++ b/Source/cmDocumentationEntry.h @@ -9,26 +9,15 @@ /** Standard documentation entry for cmDocumentation's formatting. */ struct cmDocumentationEntry { - std::string Name; - std::string Brief; - char CustomNamePrefix = ' '; - cmDocumentationEntry() = default; - cmDocumentationEntry(const char* doc[2]) - { - if (doc[0]) { - this->Name = doc[0]; - } - if (doc[1]) { - this->Brief = doc[1]; - } - } - cmDocumentationEntry(const char* n, const char* b) +#if __cplusplus <= 201103L + cmDocumentationEntry(const std::string& name, const std::string& brief) + : Name{ name } + , Brief{ brief } { - if (n) { - this->Name = n; - } - if (b) { - this->Brief = b; - } } +#endif + + std::string Name = {}; + std::string Brief = {}; + char CustomNamePrefix = ' '; }; diff --git a/Source/cmDocumentationFormatter.cxx b/Source/cmDocumentationFormatter.cxx index 732637e..70ba1fc 100644 --- a/Source/cmDocumentationFormatter.cxx +++ b/Source/cmDocumentationFormatter.cxx @@ -2,7 +2,8 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmDocumentationFormatter.h" -#include <cstring> +#include <algorithm> +#include <cassert> #include <iomanip> #include <ostream> #include <string> @@ -11,178 +12,207 @@ #include "cmDocumentationEntry.h" #include "cmDocumentationSection.h" -cmDocumentationFormatter::cmDocumentationFormatter() = default; - -cmDocumentationFormatter::~cmDocumentationFormatter() = default; +namespace { +const char* skipSpaces(const char* ptr) +{ + assert(ptr); + for (; *ptr == ' '; ++ptr) { + ; + } + return ptr; +} +const char* skipToSpace(const char* ptr) +{ + assert(ptr); + for (; *ptr && (*ptr != '\n') && (*ptr != ' '); ++ptr) { + ; + } + return ptr; +} +} void cmDocumentationFormatter::PrintFormatted(std::ostream& os, - const char* text) + std::string const& text) const { - if (!text) { + if (text.empty()) { return; } - const char* ptr = text; - while (*ptr) { - // Any ptrs starting in a space are treated as preformatted text. - std::string preformatted; - while (*ptr == ' ') { - for (char ch = *ptr; ch && ch != '\n'; ++ptr, ch = *ptr) { - preformatted.append(1, ch); - } - if (*ptr) { - ++ptr; - preformatted.append(1, '\n'); - } - } - if (!preformatted.empty()) { - this->PrintPreformatted(os, preformatted.c_str()); + + struct Buffer + { + // clang-format off + using PrinterFn = void (cmDocumentationFormatter::*)( + std::ostream&, std::string const& + ) const; + // clang-format on + std::string collected; + const PrinterFn printer; + }; + // const auto NORMAL_IDX = 0u; + const auto PREFORMATTED_IDX = 1u; + const auto HANDLERS_SIZE = 2u; + Buffer buffers[HANDLERS_SIZE] = { + { {}, &cmDocumentationFormatter::PrintParagraph }, + { {}, &cmDocumentationFormatter::PrintPreformatted } + }; + + const auto padding = std::string(this->TextIndent, ' '); + + for (std::size_t pos = 0u, eol = 0u; pos < text.size(); pos = eol) { + const auto current_idx = std::size_t(text[pos] == ' '); + // size_t(!bool(current_idx)) + const auto other_idx = current_idx ^ 1u; + + // Flush the other buffer if anything has been collected + if (!buffers[other_idx].collected.empty()) { + // NOTE Whatever the other index is, the current buffered + // string expected to be empty. + assert(buffers[current_idx].collected.empty()); + + (this->*buffers[other_idx].printer)(os, buffers[other_idx].collected); + buffers[other_idx].collected.clear(); } - // Other ptrs are treated as paragraphs. - std::string paragraph; - for (char ch = *ptr; ch && ch != '\n'; ++ptr, ch = *ptr) { - paragraph.append(1, ch); + // ATTENTION The previous implementation had called `PrintParagraph()` + // **for every processed (char by char) input line**. + // The method unconditionally append the `\n' character after the + // printed text. To keep the backward-compatible behavior it's needed to + // add the '\n' character to the previously collected line... + if (!buffers[current_idx].collected.empty() && + current_idx != PREFORMATTED_IDX) { + buffers[current_idx].collected += '\n'; } - if (*ptr) { - ++ptr; - paragraph.append(1, '\n'); + + // Lookup EOL + eol = text.find('\n', pos); + if (current_idx == PREFORMATTED_IDX) { + buffers[current_idx].collected.append(padding); } - if (!paragraph.empty()) { - this->PrintParagraph(os, paragraph.c_str()); + buffers[current_idx].collected.append( + text, pos, eol == std::string::npos ? eol : ++eol - pos); + } + + for (auto& buf : buffers) { + if (!buf.collected.empty()) { + (this->*buf.printer)(os, buf.collected); } } } void cmDocumentationFormatter::PrintPreformatted(std::ostream& os, - const char* text) + std::string const& text) const { - bool newline = true; - for (const char* ptr = text; *ptr; ++ptr) { - if (newline && *ptr != '\n') { - os << this->TextIndent; - newline = false; - } - os << *ptr; - if (*ptr == '\n') { - newline = true; - } - } - os << "\n"; + os << text << '\n'; } void cmDocumentationFormatter::PrintParagraph(std::ostream& os, - const char* text) + std::string const& text) const { - os << this->TextIndent; + if (this->TextIndent) { + os << std::string(this->TextIndent, ' '); + } this->PrintColumn(os, text); - os << "\n"; -} - -void cmDocumentationFormatter::SetIndent(const char* indent) -{ - this->TextIndent = indent; + os << '\n'; } -void cmDocumentationFormatter::PrintColumn(std::ostream& os, const char* text) +void cmDocumentationFormatter::PrintColumn(std::ostream& os, + std::string const& text) const { // Print text arranged in an indented column of fixed width. - const char* l = text; - long column = 0; bool newSentence = false; bool firstLine = true; - int width = this->TextWidth - static_cast<int>(strlen(this->TextIndent)); - // Loop until the end of the text. - while (*l) { - // Parse the next word. - const char* r = l; - while (*r && (*r != '\n') && (*r != ' ')) { - ++r; - } + assert(this->TextIndent < this->TextWidth); + const std::ptrdiff_t width = this->TextWidth - this->TextIndent; + std::ptrdiff_t column = 0; + // Loop until the end of the text. + for (const char *l = text.c_str(), *r = skipToSpace(text.c_str()); *l; + l = skipSpaces(r), r = skipToSpace(l)) { // Does it fit on this line? - if (r - l < (width - column - (newSentence ? 1 : 0))) { + if (r - l < width - column - std::ptrdiff_t(newSentence)) { // Word fits on this line. if (r > l) { if (column) { // Not first word on line. Separate from the previous word // by a space, or two if this is a new sentence. - if (newSentence) { - os << " "; - column += 2; - } else { - os << " "; - column += 1; - } - } else { + os << &(" "[std::size_t(!newSentence)]); + column += 1u + std::ptrdiff_t(newSentence); + } else if (!firstLine && this->TextIndent) { // First word on line. Print indentation unless this is the // first line. - os << (firstLine ? "" : this->TextIndent); + os << std::string(this->TextIndent, ' '); } // Print the word. - os.write(l, static_cast<long>(r - l)); + os.write(l, r - l); newSentence = (*(r - 1) == '.'); } if (*r == '\n') { // Text provided a newline. Start a new line. - os << "\n"; + os << '\n'; ++r; column = 0; firstLine = false; } else { // No provided newline. Continue this line. - column += static_cast<long>(r - l); + column += r - l; } } else { // Word does not fit on this line. Start a new line. - os << "\n"; + os << '\n'; firstLine = false; if (r > l) { - os << this->TextIndent; - os.write(l, static_cast<long>(r - l)); - column = static_cast<long>(r - l); + os << std::string(this->TextIndent, ' '); + os.write(l, r - l); + column = r - l; newSentence = (*(r - 1) == '.'); } else { column = 0; } } - // Move to beginning of next word. Skip over whitespace. - l = r; - while (*l == ' ') { - ++l; - } } } void cmDocumentationFormatter::PrintSection( std::ostream& os, cmDocumentationSection const& section) { - os << section.GetName() << "\n"; + const std::size_t PREFIX_SIZE = + sizeof(cmDocumentationEntry::CustomNamePrefix) + 1u; + // length of the "= " literal (see below) + const std::size_t SUFFIX_SIZE = 2u; + // legacy magic number ;-) + const std::size_t NAME_SIZE = 29u; + + const std::size_t PADDING_SIZE = PREFIX_SIZE + SUFFIX_SIZE; + const std::size_t TITLE_SIZE = NAME_SIZE + PADDING_SIZE; + + const auto savedIndent = this->TextIndent; - const std::vector<cmDocumentationEntry>& entries = section.GetEntries(); - for (cmDocumentationEntry const& entry : entries) { + os << section.GetName() << '\n'; + + for (cmDocumentationEntry const& entry : section.GetEntries()) { if (!entry.Name.empty()) { - os << std::setw(2) << std::left << entry.CustomNamePrefix << entry.Name; - this->TextIndent = " "; - int align = static_cast<int>(strlen(this->TextIndent)) - 4; - for (int i = static_cast<int>(entry.Name.size()); i < align; ++i) { - os << " "; - } - if (entry.Name.size() > strlen(this->TextIndent) - 4) { - os << "\n"; - os.write(this->TextIndent, strlen(this->TextIndent) - 2); + this->TextIndent = TITLE_SIZE; + os << std::setw(PREFIX_SIZE) << std::left << entry.CustomNamePrefix + << std::setw(int(std::max(NAME_SIZE, entry.Name.size()))) + << entry.Name; + if (entry.Name.size() > NAME_SIZE) { + os << '\n' << std::setw(int(this->TextIndent - PREFIX_SIZE)) << ' '; } os << "= "; - this->PrintColumn(os, entry.Brief.c_str()); - os << "\n"; + this->PrintColumn(os, entry.Brief); + os << '\n'; } else { - os << "\n"; - this->TextIndent = ""; - this->PrintFormatted(os, entry.Brief.c_str()); + os << '\n'; + this->TextIndent = 0u; + this->PrintFormatted(os, entry.Brief); } } - os << "\n"; + + os << '\n'; + + this->TextIndent = savedIndent; } diff --git a/Source/cmDocumentationFormatter.h b/Source/cmDocumentationFormatter.h index cb3038a..e269f6a 100644 --- a/Source/cmDocumentationFormatter.h +++ b/Source/cmDocumentationFormatter.h @@ -5,40 +5,7 @@ #include "cmConfigure.h" // IWYU pragma: keep #include <iosfwd> - -/** This is just a helper class to make it build with MSVC 6.0. -Actually the enums and internal classes could directly go into -cmDocumentation, but then MSVC6 complains in RequestedHelpItem that -cmDocumentation is an undefined type and so it doesn't know the enums. -Moving the enums to a class which is then already completely parsed helps -against this. */ -class cmDocumentationEnums -{ -public: - /** Types of help provided. */ - enum Type - { - None, - Version, - Usage, - Help, - Full, - ListManuals, - ListCommands, - ListModules, - ListProperties, - ListVariables, - ListPolicies, - ListGenerators, - OneManual, - OneCommand, - OneModule, - OneProperty, - OneVariable, - OnePolicy, - OldCustomModules - }; -}; +#include <string> class cmDocumentationSection; @@ -46,18 +13,15 @@ class cmDocumentationSection; class cmDocumentationFormatter { public: - cmDocumentationFormatter(); - virtual ~cmDocumentationFormatter(); - void PrintFormatted(std::ostream& os, const char* text); - - virtual void PrintSection(std::ostream& os, - cmDocumentationSection const& section); - virtual void PrintPreformatted(std::ostream& os, const char* text); - virtual void PrintParagraph(std::ostream& os, const char* text); - void PrintColumn(std::ostream& os, const char* text); - void SetIndent(const char* indent); + void SetIndent(std::size_t indent) { this->TextIndent = indent; } + void PrintFormatted(std::ostream& os, std::string const& text) const; + void PrintSection(std::ostream& os, cmDocumentationSection const& section); private: - int TextWidth = 77; - const char* TextIndent = ""; + void PrintPreformatted(std::ostream& os, std::string const&) const; + void PrintParagraph(std::ostream& os, std::string const&) const; + void PrintColumn(std::ostream& os, std::string const&) const; + + std::size_t TextWidth = 77u; + std::size_t TextIndent = 0u; }; diff --git a/Source/cmDocumentationSection.cxx b/Source/cmDocumentationSection.cxx deleted file mode 100644 index 439da1b..0000000 --- a/Source/cmDocumentationSection.cxx +++ /dev/null @@ -1,28 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#include "cmDocumentationSection.h" - -void cmDocumentationSection::Append(const char* data[][2]) -{ - int i = 0; - while (data[i][1]) { - this->Entries.emplace_back(data[i][0], data[i][1]); - data += 1; - } -} - -void cmDocumentationSection::Prepend(const char* data[][2]) -{ - std::vector<cmDocumentationEntry> tmp; - int i = 0; - while (data[i][1]) { - tmp.emplace_back(data[i][0], data[i][1]); - data += 1; - } - this->Entries.insert(this->Entries.begin(), tmp.begin(), tmp.end()); -} - -void cmDocumentationSection::Append(const char* n, const char* b) -{ - this->Entries.emplace_back(n, b); -} diff --git a/Source/cmDocumentationSection.h b/Source/cmDocumentationSection.h index 276e520..b5e24fe 100644 --- a/Source/cmDocumentationSection.h +++ b/Source/cmDocumentationSection.h @@ -4,11 +4,10 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include <iterator> #include <string> #include <vector> -#include <cmext/algorithm> - #include "cmDocumentationEntry.h" // Low-level interface for custom documents: @@ -45,21 +44,20 @@ public: { this->Entries.push_back(entry); } - void Append(const std::vector<cmDocumentationEntry>& entries) + + template <typename Iterable> + void Append(const Iterable& entries) { - cm::append(this->Entries, entries); + this->Entries.insert(std::end(this->Entries), std::begin(entries), + std::end(entries)); } - /** Append an entry to this section using NULL terminated chars */ - void Append(const char* [][2]); - void Append(const char* n, const char* b); - /** prepend some documentation to this section */ - void Prepend(const char* [][2]); - void Prepend(const std::vector<cmDocumentationEntry>& entries) + template <typename Iterable> + void Prepend(const Iterable& entries) { - this->Entries.insert(this->Entries.begin(), entries.begin(), - entries.end()); + this->Entries.insert(std::begin(this->Entries), std::begin(entries), + std::end(entries)); } private: diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx index 85f528d..cdd0408 100644 --- a/Source/cmFileCommand.cxx +++ b/Source/cmFileCommand.cxx @@ -1408,12 +1408,14 @@ bool HandleCopyFile(std::vector<std::string> const& args, struct Arguments { + bool InputMayBeRecent = false; bool OnlyIfDifferent = false; std::string Result; }; static auto const parser = cmArgumentParser<Arguments>{} + .Bind("INPUT_MAY_BE_RECENT"_s, &Arguments::InputMayBeRecent) .Bind("ONLY_IF_DIFFERENT"_s, &Arguments::OnlyIfDifferent) .Bind("RESULT"_s, &Arguments::Result); @@ -1456,9 +1458,13 @@ bool HandleCopyFile(std::vector<std::string> const& args, } else { when = cmSystemTools::CopyWhen::Always; } + cmSystemTools::CopyInputRecent const inputRecent = arguments.InputMayBeRecent + ? cmSystemTools::CopyInputRecent::Yes + : cmSystemTools::CopyInputRecent::No; std::string err; - if (cmSystemTools::CopySingleFile(oldname, newname, when, &err) == + if (cmSystemTools::CopySingleFile(oldname, newname, when, inputRecent, + &err) == cmSystemTools::CopyResult::Success) { if (!arguments.Result.empty()) { status.GetMakefile().AddDefinition(arguments.Result, "0"); diff --git a/Source/cmGeneratorExpression.cxx b/Source/cmGeneratorExpression.cxx index 21ace89..b605350 100644 --- a/Source/cmGeneratorExpression.cxx +++ b/Source/cmGeneratorExpression.cxx @@ -2,6 +2,7 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmGeneratorExpression.h" +#include <algorithm> #include <cassert> #include <memory> #include <utility> @@ -226,23 +227,33 @@ static std::string stripExportInterface( while (true) { std::string::size_type bPos = input.find("$<BUILD_INTERFACE:", lastPos); std::string::size_type iPos = input.find("$<INSTALL_INTERFACE:", lastPos); + std::string::size_type lPos = + input.find("$<BUILD_LOCAL_INTERFACE:", lastPos); - if (bPos == std::string::npos && iPos == std::string::npos) { + pos = std::min({ bPos, iPos, lPos }); + if (pos == std::string::npos) { break; } - if (bPos == std::string::npos) { - pos = iPos; - } else if (iPos == std::string::npos) { - pos = bPos; + result += input.substr(lastPos, pos - lastPos); + enum class FoundGenex + { + BuildInterface, + InstallInterface, + BuildLocalInterface, + } foundGenex = FoundGenex::BuildInterface; + if (pos == bPos) { + foundGenex = FoundGenex::BuildInterface; + pos += cmStrLen("$<BUILD_INTERFACE:"); + } else if (pos == iPos) { + foundGenex = FoundGenex::InstallInterface; + pos += cmStrLen("$<INSTALL_INTERFACE:"); + } else if (pos == lPos) { + foundGenex = FoundGenex::BuildLocalInterface; + pos += cmStrLen("$<BUILD_LOCAL_INTERFACE:"); } else { - pos = (bPos < iPos) ? bPos : iPos; + assert(false && "Invalid position found"); } - - result += input.substr(lastPos, pos - lastPos); - const bool gotInstallInterface = input[pos + 2] == 'I'; - pos += gotInstallInterface ? sizeof("$<INSTALL_INTERFACE:") - 1 - : sizeof("$<BUILD_INTERFACE:") - 1; nestingLevel = 1; const char* c = input.c_str() + pos; const char* const cStart = c; @@ -258,10 +269,10 @@ static std::string stripExportInterface( continue; } if (context == cmGeneratorExpression::BuildInterface && - !gotInstallInterface) { + foundGenex == FoundGenex::BuildInterface) { result += input.substr(pos, c - cStart); } else if (context == cmGeneratorExpression::InstallInterface && - gotInstallInterface) { + foundGenex == FoundGenex::InstallInterface) { const std::string content = input.substr(pos, c - cStart); if (resolveRelative) { prefixItems(content, result, "${_IMPORT_PREFIX}/"); @@ -274,9 +285,18 @@ static std::string stripExportInterface( } const std::string::size_type traversed = (c - cStart) + 1; if (!*c) { - result += std::string(gotInstallInterface ? "$<INSTALL_INTERFACE:" - : "$<BUILD_INTERFACE:") + - input.substr(pos, traversed); + auto remaining = input.substr(pos, traversed); + switch (foundGenex) { + case FoundGenex::BuildInterface: + result = cmStrCat(result, "$<BUILD_INTERFACE:", remaining); + break; + case FoundGenex::InstallInterface: + result = cmStrCat(result, "$<INSTALL_INTERFACE:", remaining); + break; + case FoundGenex::BuildLocalInterface: + result = cmStrCat(result, "$<BUILD_LOCAL_INTERFACE:", remaining); + break; + } } pos += traversed; lastPos = pos; diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index 562c31e..c14012e 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -114,6 +114,8 @@ static const struct OneNode buildInterfaceNode; static const struct ZeroNode installInterfaceNode; +static const struct OneNode buildLocalInterfaceNode; + struct BooleanOpNode : public cmGeneratorExpressionNode { BooleanOpNode(const char* op_, const char* successVal_, @@ -1970,7 +1972,10 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode } return std::string(); } - target = context->LG->FindGeneratorTargetToUse(targetName); + cmLocalGenerator const* lg = context->CurrentTarget + ? context->CurrentTarget->GetLocalGenerator() + : context->LG; + target = lg->FindGeneratorTargetToUse(targetName); if (!target) { std::ostringstream e; @@ -3320,6 +3325,7 @@ const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode( { "GENEX_EVAL", &genexEvalNode }, { "BUILD_INTERFACE", &buildInterfaceNode }, { "INSTALL_INTERFACE", &installInterfaceNode }, + { "BUILD_LOCAL_INTERFACE", &buildLocalInterfaceNode }, { "INSTALL_PREFIX", &installPrefixNode }, { "JOIN", &joinNode }, { "LINK_ONLY", &linkOnlyNode }, diff --git a/Source/cmGlobalBorlandMakefileGenerator.cxx b/Source/cmGlobalBorlandMakefileGenerator.cxx index 776ee40..2fd7f8a 100644 --- a/Source/cmGlobalBorlandMakefileGenerator.cxx +++ b/Source/cmGlobalBorlandMakefileGenerator.cxx @@ -60,11 +60,10 @@ cmGlobalBorlandMakefileGenerator::CreateLocalGenerator(cmMakefile* mf) return std::unique_ptr<cmLocalGenerator>(std::move(lg)); } -void cmGlobalBorlandMakefileGenerator::GetDocumentation( - cmDocumentationEntry& entry) +cmDocumentationEntry cmGlobalBorlandMakefileGenerator::GetDocumentation() { - entry.Name = cmGlobalBorlandMakefileGenerator::GetActualName(); - entry.Brief = "Generates Borland makefiles."; + return { cmGlobalBorlandMakefileGenerator::GetActualName(), + "Generates Borland makefiles." }; } std::vector<cmGlobalGenerator::GeneratedMakeCommand> diff --git a/Source/cmGlobalBorlandMakefileGenerator.h b/Source/cmGlobalBorlandMakefileGenerator.h index a280b81..049d6ba 100644 --- a/Source/cmGlobalBorlandMakefileGenerator.h +++ b/Source/cmGlobalBorlandMakefileGenerator.h @@ -13,7 +13,6 @@ class cmLocalGenerator; class cmMakefile; class cmake; -struct cmDocumentationEntry; /** \class cmGlobalBorlandMakefileGenerator * \brief Write a Borland makefiles. @@ -38,7 +37,7 @@ public: static std::string GetActualName() { return "Borland Makefiles"; } /** Get the documentation entry for this generator. */ - static void GetDocumentation(cmDocumentationEntry& entry); + static cmDocumentationEntry GetDocumentation(); //! Create a local generator appropriate to this Global Generator std::unique_ptr<cmLocalGenerator> CreateLocalGenerator( diff --git a/Source/cmGlobalGeneratorFactory.h b/Source/cmGlobalGeneratorFactory.h index d6ababb..a935079 100644 --- a/Source/cmGlobalGeneratorFactory.h +++ b/Source/cmGlobalGeneratorFactory.h @@ -4,6 +4,10 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include "cmDocumentationEntry.h" // IWYU pragma: export + +// TODO The following headers are parts of the `cmGlobalGeneratorFactory` +// public API, so could be defined as export to IWYU #include <string> #include <vector> @@ -11,7 +15,6 @@ class cmGlobalGenerator; class cmake; -struct cmDocumentationEntry; /** \class cmGlobalGeneratorFactory * \brief Responable for creating cmGlobalGenerator instances @@ -28,7 +31,7 @@ public: const std::string& n, bool allowArch, cmake* cm) const = 0; /** Get the documentation entry for this factory */ - virtual void GetDocumentation(cmDocumentationEntry& entry) const = 0; + virtual cmDocumentationEntry GetDocumentation() const = 0; /** Get the names of the current registered generators */ virtual std::vector<std::string> GetGeneratorNames() const = 0; @@ -47,7 +50,7 @@ public: virtual std::string GetDefaultPlatformName() const = 0; }; -template <class T> +template <typename T> class cmGlobalGeneratorSimpleFactory : public cmGlobalGeneratorFactory { public: @@ -62,21 +65,19 @@ public: } /** Get the documentation entry for this factory */ - void GetDocumentation(cmDocumentationEntry& entry) const override + cmDocumentationEntry GetDocumentation() const override { - T::GetDocumentation(entry); + return T::GetDocumentation(); } /** Get the names of the current registered generators */ std::vector<std::string> GetGeneratorNames() const override { - std::vector<std::string> names; - names.push_back(T::GetActualName()); - return names; + return { T::GetActualName() }; } std::vector<std::string> GetGeneratorNamesWithPlatform() const override { - return std::vector<std::string>(); + return {}; } /** Determine whether or not this generator supports toolsets */ @@ -89,8 +90,8 @@ public: std::vector<std::string> GetKnownPlatforms() const override { // default is no platform supported - return std::vector<std::string>(); + return {}; } - std::string GetDefaultPlatformName() const override { return std::string(); } + std::string GetDefaultPlatformName() const override { return {}; } }; diff --git a/Source/cmGlobalGhsMultiGenerator.cxx b/Source/cmGlobalGhsMultiGenerator.cxx index 9c334a5..18c48d7 100644 --- a/Source/cmGlobalGhsMultiGenerator.cxx +++ b/Source/cmGlobalGhsMultiGenerator.cxx @@ -15,7 +15,6 @@ #include "cmCustomCommand.h" #include "cmCustomCommandLines.h" -#include "cmDocumentationEntry.h" #include "cmGeneratedFileStream.h" #include "cmGeneratorTarget.h" #include "cmGhsMultiGpj.h" @@ -58,11 +57,12 @@ cmGlobalGhsMultiGenerator::CreateLocalGenerator(cmMakefile* mf) cm::make_unique<cmLocalGhsMultiGenerator>(this, mf)); } -void cmGlobalGhsMultiGenerator::GetDocumentation(cmDocumentationEntry& entry) +cmDocumentationEntry cmGlobalGhsMultiGenerator::GetDocumentation() { - entry.Name = GetActualName(); - entry.Brief = - "Generates Green Hills MULTI files (experimental, work-in-progress)."; + return { + GetActualName(), + "Generates Green Hills MULTI files (experimental, work-in-progress)." + }; } void cmGlobalGhsMultiGenerator::ComputeTargetObjectDirectory( diff --git a/Source/cmGlobalGhsMultiGenerator.h b/Source/cmGlobalGhsMultiGenerator.h index aa68d3b..4a79610 100644 --- a/Source/cmGlobalGhsMultiGenerator.h +++ b/Source/cmGlobalGhsMultiGenerator.h @@ -18,7 +18,6 @@ class cmGeneratorTarget; class cmLocalGenerator; class cmMakefile; class cmake; -struct cmDocumentationEntry; class cmGlobalGhsMultiGenerator : public cmGlobalGenerator { @@ -46,7 +45,7 @@ public: std::string GetName() const override { return GetActualName(); } /// Overloaded methods. @see cmGlobalGenerator::GetDocumentation() - static void GetDocumentation(cmDocumentationEntry& entry); + static cmDocumentationEntry GetDocumentation(); /** * Utilized by the generator factory to determine if this generator diff --git a/Source/cmGlobalJOMMakefileGenerator.cxx b/Source/cmGlobalJOMMakefileGenerator.cxx index 1a625cc..f1d4d09 100644 --- a/Source/cmGlobalJOMMakefileGenerator.cxx +++ b/Source/cmGlobalJOMMakefileGenerator.cxx @@ -6,7 +6,6 @@ #include <cmext/algorithm> -#include "cmDocumentationEntry.h" #include "cmGlobalGenerator.h" #include "cmMakefile.h" #include "cmState.h" @@ -36,11 +35,10 @@ void cmGlobalJOMMakefileGenerator::EnableLanguage( this->cmGlobalUnixMakefileGenerator3::EnableLanguage(l, mf, optional); } -void cmGlobalJOMMakefileGenerator::GetDocumentation( - cmDocumentationEntry& entry) +cmDocumentationEntry cmGlobalJOMMakefileGenerator::GetDocumentation() { - entry.Name = cmGlobalJOMMakefileGenerator::GetActualName(); - entry.Brief = "Generates JOM makefiles."; + return { cmGlobalJOMMakefileGenerator::GetActualName(), + "Generates JOM makefiles." }; } void cmGlobalJOMMakefileGenerator::PrintCompilerAdvice(std::ostream& os, diff --git a/Source/cmGlobalJOMMakefileGenerator.h b/Source/cmGlobalJOMMakefileGenerator.h index 332d1cf..5e74875 100644 --- a/Source/cmGlobalJOMMakefileGenerator.h +++ b/Source/cmGlobalJOMMakefileGenerator.h @@ -13,7 +13,6 @@ class cmMakefile; class cmake; -struct cmDocumentationEntry; /** \class cmGlobalJOMMakefileGenerator * \brief Write a JOM makefiles. @@ -39,7 +38,7 @@ public: static std::string GetActualName() { return "NMake Makefiles JOM"; } /** Get the documentation entry for this generator. */ - static void GetDocumentation(cmDocumentationEntry& entry); + static cmDocumentationEntry GetDocumentation(); /** * Try to determine system information such as shared library diff --git a/Source/cmGlobalMSYSMakefileGenerator.cxx b/Source/cmGlobalMSYSMakefileGenerator.cxx index d4ff1e0..e543aea 100644 --- a/Source/cmGlobalMSYSMakefileGenerator.cxx +++ b/Source/cmGlobalMSYSMakefileGenerator.cxx @@ -4,7 +4,6 @@ #include "cmsys/FStream.hxx" -#include "cmDocumentationEntry.h" #include "cmMakefile.h" #include "cmState.h" #include "cmStringAlgorithms.h" @@ -53,9 +52,8 @@ void cmGlobalMSYSMakefileGenerator::EnableLanguage( } } -void cmGlobalMSYSMakefileGenerator::GetDocumentation( - cmDocumentationEntry& entry) +cmDocumentationEntry cmGlobalMSYSMakefileGenerator::GetDocumentation() { - entry.Name = cmGlobalMSYSMakefileGenerator::GetActualName(); - entry.Brief = "Generates MSYS makefiles."; + return { cmGlobalMSYSMakefileGenerator::GetActualName(), + "Generates MSYS makefiles." }; } diff --git a/Source/cmGlobalMSYSMakefileGenerator.h b/Source/cmGlobalMSYSMakefileGenerator.h index 586487f..a8516a4 100644 --- a/Source/cmGlobalMSYSMakefileGenerator.h +++ b/Source/cmGlobalMSYSMakefileGenerator.h @@ -11,7 +11,6 @@ class cmMakefile; class cmake; -struct cmDocumentationEntry; /** \class cmGlobalMSYSMakefileGenerator * \brief Write a NMake makefiles. @@ -36,7 +35,7 @@ public: static std::string GetActualName() { return "MSYS Makefiles"; } /** Get the documentation entry for this generator. */ - static void GetDocumentation(cmDocumentationEntry& entry); + static cmDocumentationEntry GetDocumentation(); /** * Try to determine system information such as shared library diff --git a/Source/cmGlobalMinGWMakefileGenerator.cxx b/Source/cmGlobalMinGWMakefileGenerator.cxx index 5a7edae..a0a52d3 100644 --- a/Source/cmGlobalMinGWMakefileGenerator.cxx +++ b/Source/cmGlobalMinGWMakefileGenerator.cxx @@ -2,7 +2,6 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmGlobalMinGWMakefileGenerator.h" -#include "cmDocumentationEntry.h" #include "cmMakefile.h" #include "cmState.h" #include "cmSystemTools.h" @@ -19,9 +18,8 @@ cmGlobalMinGWMakefileGenerator::cmGlobalMinGWMakefileGenerator(cmake* cm) cm->GetState()->SetMinGWMake(true); } -void cmGlobalMinGWMakefileGenerator::GetDocumentation( - cmDocumentationEntry& entry) +cmDocumentationEntry cmGlobalMinGWMakefileGenerator::GetDocumentation() { - entry.Name = cmGlobalMinGWMakefileGenerator::GetActualName(); - entry.Brief = "Generates a make file for use with mingw32-make."; + return { cmGlobalMinGWMakefileGenerator::GetActualName(), + "Generates a make file for use with mingw32-make." }; } diff --git a/Source/cmGlobalMinGWMakefileGenerator.h b/Source/cmGlobalMinGWMakefileGenerator.h index 92d495c..b39db03 100644 --- a/Source/cmGlobalMinGWMakefileGenerator.h +++ b/Source/cmGlobalMinGWMakefileGenerator.h @@ -11,7 +11,6 @@ class cmMakefile; class cmake; -struct cmDocumentationEntry; /** \class cmGlobalMinGWMakefileGenerator * \brief Write a NMake makefiles. @@ -35,5 +34,5 @@ public: static std::string GetActualName() { return "MinGW Makefiles"; } /** Get the documentation entry for this generator. */ - static void GetDocumentation(cmDocumentationEntry& entry); + static cmDocumentationEntry GetDocumentation(); }; diff --git a/Source/cmGlobalNMakeMakefileGenerator.cxx b/Source/cmGlobalNMakeMakefileGenerator.cxx index eabacf6..cb53850 100644 --- a/Source/cmGlobalNMakeMakefileGenerator.cxx +++ b/Source/cmGlobalNMakeMakefileGenerator.cxx @@ -8,7 +8,6 @@ #include "cmsys/RegularExpression.hxx" -#include "cmDocumentationEntry.h" #include "cmDuration.h" #include "cmGlobalGenerator.h" #include "cmMakefile.h" @@ -80,11 +79,10 @@ void cmGlobalNMakeMakefileGenerator::CheckNMakeFeatures() cmSystemTools::OP_LESS, this->NMakeVersion, "9"); } -void cmGlobalNMakeMakefileGenerator::GetDocumentation( - cmDocumentationEntry& entry) +cmDocumentationEntry cmGlobalNMakeMakefileGenerator::GetDocumentation() { - entry.Name = cmGlobalNMakeMakefileGenerator::GetActualName(); - entry.Brief = "Generates NMake makefiles."; + return { cmGlobalNMakeMakefileGenerator::GetActualName(), + "Generates NMake makefiles." }; } void cmGlobalNMakeMakefileGenerator::PrintCompilerAdvice( @@ -128,12 +126,8 @@ void cmGlobalNMakeMakefileGenerator::PrintBuildCommandAdvice(std::ostream& os, if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) { // nmake does not support parallel build level // see https://msdn.microsoft.com/en-us/library/afyyse50.aspx - - /* clang-format off */ - os << - "Warning: NMake does not support parallel builds. " - "Ignoring parallel build command line option.\n"; - /* clang-format on */ + os << "Warning: NMake does not support parallel builds. " + "Ignoring parallel build command line option.\n"; } this->cmGlobalUnixMakefileGenerator3::PrintBuildCommandAdvice( diff --git a/Source/cmGlobalNMakeMakefileGenerator.h b/Source/cmGlobalNMakeMakefileGenerator.h index b3574eb..436ebca 100644 --- a/Source/cmGlobalNMakeMakefileGenerator.h +++ b/Source/cmGlobalNMakeMakefileGenerator.h @@ -15,7 +15,6 @@ class cmMakefile; class cmake; -struct cmDocumentationEntry; /** \class cmGlobalNMakeMakefileGenerator * \brief Write a NMake makefiles. @@ -45,7 +44,7 @@ public: } /** Get the documentation entry for this generator. */ - static void GetDocumentation(cmDocumentationEntry& entry); + static cmDocumentationEntry GetDocumentation(); /** * Try to determine system information such as shared library diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index 395372b..aa1ded0 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -25,7 +25,6 @@ #include "cmsys/FStream.hxx" #include "cmCxxModuleMapper.h" -#include "cmDocumentationEntry.h" #include "cmFileSet.h" #include "cmFortranParser.h" #include "cmGeneratedFileStream.h" @@ -554,10 +553,10 @@ codecvt::Encoding cmGlobalNinjaGenerator::GetMakefileEncoding() const return this->NinjaExpectedEncoding; } -void cmGlobalNinjaGenerator::GetDocumentation(cmDocumentationEntry& entry) +cmDocumentationEntry cmGlobalNinjaGenerator::GetDocumentation() { - entry.Name = cmGlobalNinjaGenerator::GetActualName(); - entry.Brief = "Generates build.ninja files."; + return { cmGlobalNinjaGenerator::GetActualName(), + "Generates build.ninja files." }; } // Implemented in all cmGlobaleGenerator sub-classes. @@ -3211,10 +3210,10 @@ cmGlobalNinjaMultiGenerator::cmGlobalNinjaMultiGenerator(cmake* cm) cm->GetState()->SetNinjaMulti(true); } -void cmGlobalNinjaMultiGenerator::GetDocumentation(cmDocumentationEntry& entry) +cmDocumentationEntry cmGlobalNinjaMultiGenerator::GetDocumentation() { - entry.Name = cmGlobalNinjaMultiGenerator::GetActualName(); - entry.Brief = "Generates build-<Config>.ninja files."; + return { cmGlobalNinjaMultiGenerator::GetActualName(), + "Generates build-<Config>.ninja files." }; } std::string cmGlobalNinjaMultiGenerator::ExpandCFGIntDir( diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h index dac1c52..1628349 100644 --- a/Source/cmGlobalNinjaGenerator.h +++ b/Source/cmGlobalNinjaGenerator.h @@ -35,7 +35,6 @@ class cmMakefile; class cmOutputConverter; class cmStateDirectory; class cmake; -struct cmDocumentationEntry; /** * \class cmGlobalNinjaGenerator @@ -193,7 +192,7 @@ public: /** Get encoding used by generator for ninja files */ codecvt::Encoding GetMakefileEncoding() const override; - static void GetDocumentation(cmDocumentationEntry& entry); + static cmDocumentationEntry GetDocumentation(); void EnableLanguage(std::vector<std::string> const& languages, cmMakefile* mf, bool optional) override; @@ -656,7 +655,7 @@ public: new cmGlobalGeneratorSimpleFactory<cmGlobalNinjaMultiGenerator>()); } - static void GetDocumentation(cmDocumentationEntry& entry); + static cmDocumentationEntry GetDocumentation(); std::string GetName() const override { diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx index bf9e40e..70a9d3e 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.cxx +++ b/Source/cmGlobalUnixMakefileGenerator3.cxx @@ -11,7 +11,6 @@ #include <cmext/algorithm> #include <cmext/memory> -#include "cmDocumentationEntry.h" #include "cmGeneratedFileStream.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" @@ -71,11 +70,10 @@ cmGlobalUnixMakefileGenerator3::CreateLocalGenerator(cmMakefile* mf) cm::make_unique<cmLocalUnixMakefileGenerator3>(this, mf)); } -void cmGlobalUnixMakefileGenerator3::GetDocumentation( - cmDocumentationEntry& entry) +cmDocumentationEntry cmGlobalUnixMakefileGenerator3::GetDocumentation() { - entry.Name = cmGlobalUnixMakefileGenerator3::GetActualName(); - entry.Brief = "Generates standard UNIX makefiles."; + return { cmGlobalUnixMakefileGenerator3::GetActualName(), + "Generates standard UNIX makefiles." }; } void cmGlobalUnixMakefileGenerator3::ComputeTargetObjectDirectory( diff --git a/Source/cmGlobalUnixMakefileGenerator3.h b/Source/cmGlobalUnixMakefileGenerator3.h index 92e567a..214ba2a 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.h +++ b/Source/cmGlobalUnixMakefileGenerator3.h @@ -24,7 +24,6 @@ class cmLocalUnixMakefileGenerator3; class cmMakefile; class cmMakefileTargetGenerator; class cmake; -struct cmDocumentationEntry; /** \class cmGlobalUnixMakefileGenerator3 * \brief Write a Unix makefiles. @@ -101,7 +100,7 @@ public: bool SupportsCustomCommandDepfile() const override { return true; } /** Get the documentation entry for this generator. */ - static void GetDocumentation(cmDocumentationEntry& entry); + static cmDocumentationEntry GetDocumentation(); std::unique_ptr<cmLocalGenerator> CreateLocalGenerator( cmMakefile* mf) override; diff --git a/Source/cmGlobalVisualStudio11Generator.cxx b/Source/cmGlobalVisualStudio11Generator.cxx index c53ddf5..75e3df8 100644 --- a/Source/cmGlobalVisualStudio11Generator.cxx +++ b/Source/cmGlobalVisualStudio11Generator.cxx @@ -7,7 +7,6 @@ #include <utility> #include <vector> -#include "cmDocumentationEntry.h" #include "cmGlobalGenerator.h" #include "cmGlobalGeneratorFactory.h" #include "cmGlobalVisualStudioGenerator.h" @@ -74,11 +73,11 @@ public: return std::unique_ptr<cmGlobalGenerator>(std::move(ret)); } - void GetDocumentation(cmDocumentationEntry& entry) const override + cmDocumentationEntry GetDocumentation() const override { - entry.Name = std::string(vs11generatorName) + " [arch]"; - entry.Brief = "Deprecated. Generates Visual Studio 2012 project files. " - "Optional [arch] can be \"Win64\" or \"ARM\"."; + return { std::string(vs11generatorName) + " [arch]", + "Deprecated. Generates Visual Studio 2012 project files. " + "Optional [arch] can be \"Win64\" or \"ARM\"." }; } std::vector<std::string> GetGeneratorNames() const override diff --git a/Source/cmGlobalVisualStudio12Generator.cxx b/Source/cmGlobalVisualStudio12Generator.cxx index 600ee0a..7e56a78 100644 --- a/Source/cmGlobalVisualStudio12Generator.cxx +++ b/Source/cmGlobalVisualStudio12Generator.cxx @@ -6,7 +6,6 @@ #include <sstream> #include <vector> -#include "cmDocumentationEntry.h" #include "cmGlobalGenerator.h" #include "cmGlobalGeneratorFactory.h" #include "cmGlobalVisualStudioGenerator.h" @@ -62,11 +61,11 @@ public: return std::unique_ptr<cmGlobalGenerator>(); } - void GetDocumentation(cmDocumentationEntry& entry) const override + cmDocumentationEntry GetDocumentation() const override { - entry.Name = std::string(vs12generatorName) + " [arch]"; - entry.Brief = "Generates Visual Studio 2013 project files. " - "Optional [arch] can be \"Win64\" or \"ARM\"."; + return { std::string(vs12generatorName) + " [arch]", + "Generates Visual Studio 2013 project files. " + "Optional [arch] can be \"Win64\" or \"ARM\"." }; } std::vector<std::string> GetGeneratorNames() const override diff --git a/Source/cmGlobalVisualStudio14Generator.cxx b/Source/cmGlobalVisualStudio14Generator.cxx index 9f94cca..0e05083 100644 --- a/Source/cmGlobalVisualStudio14Generator.cxx +++ b/Source/cmGlobalVisualStudio14Generator.cxx @@ -7,7 +7,6 @@ #include <cm/vector> -#include "cmDocumentationEntry.h" #include "cmGlobalGenerator.h" #include "cmGlobalGeneratorFactory.h" #include "cmGlobalVisualStudioGenerator.h" @@ -64,11 +63,11 @@ public: return std::unique_ptr<cmGlobalGenerator>(); } - void GetDocumentation(cmDocumentationEntry& entry) const override + cmDocumentationEntry GetDocumentation() const override { - entry.Name = std::string(vs14generatorName) + " [arch]"; - entry.Brief = "Generates Visual Studio 2015 project files. " - "Optional [arch] can be \"Win64\" or \"ARM\"."; + return { std::string(vs14generatorName) + " [arch]", + "Generates Visual Studio 2015 project files. " + "Optional [arch] can be \"Win64\" or \"ARM\"." }; } std::vector<std::string> GetGeneratorNames() const override diff --git a/Source/cmGlobalVisualStudio9Generator.cxx b/Source/cmGlobalVisualStudio9Generator.cxx index e03e665..cd0b114 100644 --- a/Source/cmGlobalVisualStudio9Generator.cxx +++ b/Source/cmGlobalVisualStudio9Generator.cxx @@ -6,7 +6,6 @@ #include <utility> #include <vector> -#include "cmDocumentationEntry.h" #include "cmGlobalGenerator.h" #include "cmGlobalGeneratorFactory.h" #include "cmGlobalVisualStudioGenerator.h" @@ -62,11 +61,11 @@ public: return std::unique_ptr<cmGlobalGenerator>(std::move(ret)); } - void GetDocumentation(cmDocumentationEntry& entry) const override + cmDocumentationEntry GetDocumentation() const override { - entry.Name = std::string(vs9generatorName) + " [arch]"; - entry.Brief = "Generates Visual Studio 2008 project files. " - "Optional [arch] can be \"Win64\" or \"IA64\"."; + return { std::string(vs9generatorName) + " [arch]", + "Generates Visual Studio 2008 project files. " + "Optional [arch] can be \"Win64\" or \"IA64\"." }; } std::vector<std::string> GetGeneratorNames() const override diff --git a/Source/cmGlobalVisualStudioVersionedGenerator.cxx b/Source/cmGlobalVisualStudioVersionedGenerator.cxx index be318c1..ee24f05 100644 --- a/Source/cmGlobalVisualStudioVersionedGenerator.cxx +++ b/Source/cmGlobalVisualStudioVersionedGenerator.cxx @@ -14,7 +14,6 @@ #include "cmsys/Glob.hxx" #include "cmsys/RegularExpression.hxx" -#include "cmDocumentationEntry.h" #include "cmGlobalGenerator.h" #include "cmGlobalGeneratorFactory.h" #include "cmMakefile.h" @@ -255,11 +254,11 @@ public: return std::unique_ptr<cmGlobalGenerator>(); } - void GetDocumentation(cmDocumentationEntry& entry) const override + cmDocumentationEntry GetDocumentation() const override { - entry.Name = std::string(vs15generatorName) + " [arch]"; - entry.Brief = "Generates Visual Studio 2017 project files. " - "Optional [arch] can be \"Win64\" or \"ARM\"."; + return { std::string(vs15generatorName) + " [arch]", + "Generates Visual Studio 2017 project files. " + "Optional [arch] can be \"Win64\" or \"ARM\"." }; } std::vector<std::string> GetGeneratorNames() const override @@ -351,11 +350,11 @@ public: return std::unique_ptr<cmGlobalGenerator>(); } - void GetDocumentation(cmDocumentationEntry& entry) const override + cmDocumentationEntry GetDocumentation() const override { - entry.Name = std::string(vs16generatorName); - entry.Brief = "Generates Visual Studio 2019 project files. " - "Use -A option to specify architecture."; + return { std::string(vs16generatorName), + "Generates Visual Studio 2019 project files. " + "Use -A option to specify architecture." }; } std::vector<std::string> GetGeneratorNames() const override @@ -416,11 +415,11 @@ public: return std::unique_ptr<cmGlobalGenerator>(); } - void GetDocumentation(cmDocumentationEntry& entry) const override + cmDocumentationEntry GetDocumentation() const override { - entry.Name = std::string(vs17generatorName); - entry.Brief = "Generates Visual Studio 2022 project files. " - "Use -A option to specify architecture."; + return { std::string(vs17generatorName), + "Generates Visual Studio 2022 project files. " + "Use -A option to specify architecture." }; } std::vector<std::string> GetGeneratorNames() const override diff --git a/Source/cmGlobalWatcomWMakeGenerator.cxx b/Source/cmGlobalWatcomWMakeGenerator.cxx index fb2a8b6..ed44e6b 100644 --- a/Source/cmGlobalWatcomWMakeGenerator.cxx +++ b/Source/cmGlobalWatcomWMakeGenerator.cxx @@ -4,7 +4,6 @@ #include <ostream> -#include "cmDocumentationEntry.h" #include "cmGlobalGenerator.h" #include "cmMakefile.h" #include "cmState.h" @@ -54,11 +53,10 @@ bool cmGlobalWatcomWMakeGenerator::SetSystemName(std::string const& s, return this->cmGlobalUnixMakefileGenerator3::SetSystemName(s, mf); } -void cmGlobalWatcomWMakeGenerator::GetDocumentation( - cmDocumentationEntry& entry) +cmDocumentationEntry cmGlobalWatcomWMakeGenerator::GetDocumentation() { - entry.Name = cmGlobalWatcomWMakeGenerator::GetActualName(); - entry.Brief = "Generates Watcom WMake makefiles."; + return { cmGlobalWatcomWMakeGenerator::GetActualName(), + "Generates Watcom WMake makefiles." }; } std::vector<cmGlobalGenerator::GeneratedMakeCommand> diff --git a/Source/cmGlobalWatcomWMakeGenerator.h b/Source/cmGlobalWatcomWMakeGenerator.h index eb93934..5579120 100644 --- a/Source/cmGlobalWatcomWMakeGenerator.h +++ b/Source/cmGlobalWatcomWMakeGenerator.h @@ -15,7 +15,6 @@ class cmMakefile; class cmake; -struct cmDocumentationEntry; /** \class cmGlobalWatcomWMakeGenerator * \brief Write a NMake makefiles. @@ -39,7 +38,7 @@ public: static std::string GetActualName() { return "Watcom WMake"; } /** Get the documentation entry for this generator. */ - static void GetDocumentation(cmDocumentationEntry& entry); + static cmDocumentationEntry GetDocumentation(); /** Tell the generator about the target system. */ bool SetSystemName(std::string const& s, cmMakefile* mf) override; diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 62e5a1e..0e94de5 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -24,7 +24,6 @@ #include "cmCustomCommandGenerator.h" #include "cmCustomCommandLines.h" #include "cmCustomCommandTypes.h" -#include "cmDocumentationEntry.h" #include "cmGeneratedFileStream.h" #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" @@ -149,9 +148,9 @@ public: std::unique_ptr<cmGlobalGenerator> CreateGlobalGenerator( const std::string& name, bool allowArch, cmake* cm) const override; - void GetDocumentation(cmDocumentationEntry& entry) const override + cmDocumentationEntry GetDocumentation() const override { - cmGlobalXCodeGenerator::GetDocumentation(entry); + return cmGlobalXCodeGenerator::GetDocumentation(); } std::vector<std::string> GetGeneratorNames() const override @@ -4864,10 +4863,10 @@ std::string cmGlobalXCodeGenerator::ExpandCFGIntDir( return tmp; } -void cmGlobalXCodeGenerator::GetDocumentation(cmDocumentationEntry& entry) +cmDocumentationEntry cmGlobalXCodeGenerator::GetDocumentation() { - entry.Name = cmGlobalXCodeGenerator::GetActualName(); - entry.Brief = "Generate Xcode project files."; + return { cmGlobalXCodeGenerator::GetActualName(), + "Generate Xcode project files." }; } std::string cmGlobalXCodeGenerator::ConvertToRelativeForMake( diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h index 9ae75fb..856852b 100644 --- a/Source/cmGlobalXCodeGenerator.h +++ b/Source/cmGlobalXCodeGenerator.h @@ -14,6 +14,7 @@ #include <cm/optional> #include <cm/string_view> +#include "cmDocumentationEntry.h" #include "cmGlobalGenerator.h" #include "cmTransformDepfile.h" #include "cmValue.h" @@ -28,7 +29,6 @@ class cmMakefile; class cmSourceFile; class cmSourceGroup; class cmake; -struct cmDocumentationEntry; /** \class cmGlobalXCodeGenerator * \brief Write a Unix makefiles. @@ -54,7 +54,7 @@ public: static std::string GetActualName() { return "Xcode"; } /** Get the documentation entry for this generator. */ - static void GetDocumentation(cmDocumentationEntry& entry); + static cmDocumentationEntry GetDocumentation(); //! Create a local generator appropriate to this Global Generator std::unique_ptr<cmLocalGenerator> CreateLocalGenerator( diff --git a/Source/cmMessenger.cxx b/Source/cmMessenger.cxx index 333003b..ff513be 100644 --- a/Source/cmMessenger.cxx +++ b/Source/cmMessenger.cxx @@ -107,8 +107,8 @@ static void printMessageText(std::ostream& msg, std::string const& text) { msg << ":\n"; cmDocumentationFormatter formatter; - formatter.SetIndent(" "); - formatter.PrintFormatted(msg, text.c_str()); + formatter.SetIndent(2u); + formatter.PrintFormatted(msg, text); } static void displayMessage(MessageType t, std::ostringstream& msg) diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index 895a4c3..21409d7 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -1112,7 +1112,9 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement( this->GetObjectFilePath(source, config)); } } - linkBuild.Outputs.push_back(vars["SWIFT_MODULE"]); + if (targetType != cmStateEnums::EXECUTABLE) { + linkBuild.Outputs.push_back(vars["SWIFT_MODULE"]); + } } else { linkBuild.ExplicitDeps = this->GetObjects(config); } diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 78d230e..f94c4d3 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -1111,16 +1111,9 @@ bool cmMoveFile(std::wstring const& oldname, std::wstring const& newname, } #endif -bool cmSystemTools::CopySingleFile(const std::string& oldname, - const std::string& newname) -{ - return cmSystemTools::CopySingleFile(oldname, newname, CopyWhen::Always) == - CopyResult::Success; -} - cmSystemTools::CopyResult cmSystemTools::CopySingleFile( std::string const& oldname, std::string const& newname, CopyWhen when, - std::string* err) + CopyInputRecent inputRecent, std::string* err) { switch (when) { case CopyWhen::Always: @@ -1144,7 +1137,24 @@ cmSystemTools::CopyResult cmSystemTools::CopySingleFile( status = cmsys::SystemTools::CloneFileContent(oldname, newname); if (!status) { // if cloning did not succeed, fall back to blockwise copy +#ifdef _WIN32 + if (inputRecent == CopyInputRecent::Yes) { + // Windows sometimes locks a file immediately after creation. + // Retry a few times. + WindowsFileRetry retry = cmSystemTools::GetWindowsFileRetry(); + while ((status = + cmsys::SystemTools::CopyFileContentBlockwise(oldname, newname), + status.Path == cmsys::SystemTools::CopyStatus::SourcePath && + status.GetPOSIX() == EACCES && --retry.Count)) { + cmSystemTools::Delay(retry.Delay); + } + } else { + status = cmsys::SystemTools::CopyFileContentBlockwise(oldname, newname); + } +#else + static_cast<void>(inputRecent); status = cmsys::SystemTools::CopyFileContentBlockwise(oldname, newname); +#endif } if (!status) { if (err) { diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h index 87b354c..09f2bf0 100644 --- a/Source/cmSystemTools.h +++ b/Source/cmSystemTools.h @@ -149,6 +149,11 @@ public: Always, OnlyIfDifferent, }; + enum class CopyInputRecent + { + No, + Yes, + }; enum class CopyResult { Success, @@ -177,10 +182,9 @@ public: const mode_t* mode = nullptr); /** Copy a file. */ - static bool CopySingleFile(const std::string& oldname, - const std::string& newname); static CopyResult CopySingleFile(std::string const& oldname, std::string const& newname, CopyWhen when, + CopyInputRecent inputRecent, std::string* err = nullptr); enum class Replace diff --git a/Source/cmVersionConfig.h.in b/Source/cmVersionConfig.h.in index 06251f3..5d52950 100644 --- a/Source/cmVersionConfig.h.in +++ b/Source/cmVersionConfig.h.in @@ -1,5 +1,7 @@ /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + #define CMake_VERSION_MAJOR @CMake_VERSION_MAJOR@ #define CMake_VERSION_MINOR @CMake_VERSION_MINOR@ #define CMake_VERSION_PATCH @CMake_VERSION_PATCH@ diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 36c0089..befcb55 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -40,7 +40,6 @@ #include "cmCommands.h" #include "cmDocumentation.h" #include "cmDocumentationEntry.h" -#include "cmDocumentationFormatter.h" #include "cmDuration.h" #include "cmExternalMakefileProjectGenerator.h" #include "cmFileTimeCache.h" @@ -150,21 +149,136 @@ auto IgnoreAndTrueLambda = [](std::string const&, cmake*) -> bool { using CommandArgument = cmCommandLineArgument<bool(std::string const& value, cmake* state)>; -} // namespace - -static bool cmakeCheckStampFile(const std::string& stampName); -static bool cmakeCheckStampList(const std::string& stampList); - #ifndef CMAKE_BOOTSTRAP -static void cmWarnUnusedCliWarning(const std::string& variable, int /*unused*/, - void* ctx, const char* /*unused*/, - const cmMakefile* /*unused*/) +void cmWarnUnusedCliWarning(const std::string& variable, int /*unused*/, + void* ctx, const char* /*unused*/, + const cmMakefile* /*unused*/) { cmake* cm = reinterpret_cast<cmake*>(ctx); cm->MarkCliAsUsed(variable); } #endif +bool cmakeCheckStampFile(const std::string& stampName) +{ + // The stamp file does not exist. Use the stamp dependencies to + // determine whether it is really out of date. This works in + // conjunction with cmLocalVisualStudio7Generator to avoid + // repeatedly re-running CMake when the user rebuilds the entire + // solution. + std::string stampDepends = cmStrCat(stampName, ".depend"); +#if defined(_WIN32) || defined(__CYGWIN__) + cmsys::ifstream fin(stampDepends.c_str(), std::ios::in | std::ios::binary); +#else + cmsys::ifstream fin(stampDepends.c_str()); +#endif + if (!fin) { + // The stamp dependencies file cannot be read. Just assume the + // build system is really out of date. + std::cout << "CMake is re-running because " << stampName + << " dependency file is missing.\n"; + return false; + } + + // Compare the stamp dependencies against the dependency file itself. + { + cmFileTimeCache ftc; + std::string dep; + while (cmSystemTools::GetLineFromStream(fin, dep)) { + int result; + if (!dep.empty() && dep[0] != '#' && + (!ftc.Compare(stampDepends, dep, &result) || result < 0)) { + // The stamp depends file is older than this dependency. The + // build system is really out of date. + /* clang-format off */ + std::cout << "CMake is re-running because " << stampName + << " is out-of-date.\n" + " the file '" << dep << "'\n" + " is newer than '" << stampDepends << "'\n" + " result='" << result << "'\n"; + /* clang-format on */ + return false; + } + } + } + + // The build system is up to date. The stamp file has been removed + // by the VS IDE due to a "rebuild" request. Restore it atomically. + std::ostringstream stampTempStream; + stampTempStream << stampName << ".tmp" << cmSystemTools::RandomSeed(); + std::string stampTemp = stampTempStream.str(); + { + // TODO: Teach cmGeneratedFileStream to use a random temp file (with + // multiple tries in unlikely case of conflict) and use that here. + cmsys::ofstream stamp(stampTemp.c_str()); + stamp << "# CMake generation timestamp file for this directory.\n"; + } + std::string err; + if (cmSystemTools::RenameFile(stampTemp, stampName, + cmSystemTools::Replace::Yes, &err) == + cmSystemTools::RenameResult::Success) { + // CMake does not need to re-run because the stamp file is up-to-date. + return true; + } + cmSystemTools::RemoveFile(stampTemp); + cmSystemTools::Error( + cmStrCat("Cannot restore timestamp \"", stampName, "\": ", err)); + return false; +} + +bool cmakeCheckStampList(const std::string& stampList) +{ + // If the stamp list does not exist CMake must rerun to generate it. + if (!cmSystemTools::FileExists(stampList)) { + std::cout << "CMake is re-running because generate.stamp.list " + "is missing.\n"; + return false; + } + cmsys::ifstream fin(stampList.c_str()); + if (!fin) { + std::cout << "CMake is re-running because generate.stamp.list " + "could not be read.\n"; + return false; + } + + // Check each stamp. + std::string stampName; + while (cmSystemTools::GetLineFromStream(fin, stampName)) { + if (!cmakeCheckStampFile(stampName)) { + return false; + } + } + return true; +} + +} // namespace + +cmDocumentationEntry cmake::CMAKE_STANDARD_OPTIONS_TABLE[18] = { + { "-S <path-to-source>", "Explicitly specify a source directory." }, + { "-B <path-to-build>", "Explicitly specify a build directory." }, + { "-C <initial-cache>", "Pre-load a script to populate the cache." }, + { "-D <var>[:<type>]=<value>", "Create or update a cmake cache entry." }, + { "-U <globbing_expr>", "Remove matching entries from CMake cache." }, + { "-G <generator-name>", "Specify a build system generator." }, + { "-T <toolset-name>", "Specify toolset name if supported by generator." }, + { "-A <platform-name>", "Specify platform name if supported by generator." }, + { "--toolchain <file>", "Specify toolchain file [CMAKE_TOOLCHAIN_FILE]." }, + { "--install-prefix <directory>", + "Specify install directory [CMAKE_INSTALL_PREFIX]." }, + { "-Wdev", "Enable developer warnings." }, + { "-Wno-dev", "Suppress developer warnings." }, + { "-Werror=dev", "Make developer warnings errors." }, + { "-Wno-error=dev", "Make developer warnings not errors." }, + { "-Wdeprecated", "Enable deprecation warnings." }, + { "-Wno-deprecated", "Suppress deprecation warnings." }, + { "-Werror=deprecated", + "Make deprecated macro and function warnings " + "errors." }, + { "-Wno-error=deprecated", + "Make deprecated macro and function warnings " + "not errors." } +}; + cmake::cmake(Role role, cmState::Mode mode, cmState::ProjectKind projectKind) : CMakeWorkingDirectory(cmSystemTools::GetCurrentWorkingDirectory()) , FileTimeCache(cm::make_unique<cmFileTimeCache>()) @@ -1008,7 +1122,7 @@ void cmake::SetArgs(const std::vector<std::string>& args) std::cout << "Running with debug output on for the 'find' commands " "for package(s)"; for (auto const& v : find_pkgs) { - std::cout << " " << v; + std::cout << ' ' << v; state->SetDebugFindOutputPkgs(v); } std::cout << ".\n"; @@ -1021,7 +1135,7 @@ void cmake::SetArgs(const std::vector<std::string>& args) std::vector<std::string> find_vars(cmTokenize(value, ",")); std::cout << "Running with debug output on for the variable(s)"; for (auto const& v : find_vars) { - std::cout << " " << v; + std::cout << ' ' << v; state->SetDebugFindOutputVars(v); } std::cout << ".\n"; @@ -1082,7 +1196,7 @@ void cmake::SetArgs(const std::vector<std::string>& args) [](std::string const&, cmake* state) -> bool { std::cout << "Not searching for unused variables given on the " - << "command line.\n"; + "command line.\n"; state->SetWarnUnusedCli(false); return true; } }, @@ -1090,7 +1204,7 @@ void cmake::SetArgs(const std::vector<std::string>& args) "--check-system-vars", CommandArgument::Values::Zero, [](std::string const&, cmake* state) -> bool { std::cout << "Also check system files when warning about unused and " - << "uninitialized variables.\n"; + "uninitialized variables.\n"; state->SetCheckSystemVars(true); return true; } }, @@ -1098,7 +1212,7 @@ void cmake::SetArgs(const std::vector<std::string>& args) "--compile-no-warning-as-error", CommandArgument::Values::Zero, [](std::string const&, cmake* state) -> bool { std::cout << "Ignoring COMPILE_WARNING_AS_ERROR target property and " - << "CMAKE_COMPILE_WARNING_AS_ERROR variable.\n"; + "CMAKE_COMPILE_WARNING_AS_ERROR variable.\n"; state->SetIgnoreWarningAsError(true); return true; } } @@ -1497,7 +1611,7 @@ void cmake::SetTraceFile(const std::string& file) cmSystemTools::Error(ss.str()); return; } - std::cout << "Trace will be written to " << file << "\n"; + std::cout << "Trace will be written to " << file << '\n'; } void cmake::PrintTraceFormatVersion() @@ -2020,12 +2134,10 @@ int cmake::HandleDeleteCacheVariables(const std::string& var) } std::vector<SaveCacheEntry> saved; std::ostringstream warning; - /* clang-format off */ warning << "You have changed variables that require your cache to be deleted.\n" - << "Configure will be re-run and you may have to reset some variables.\n" - << "The following variables have changed:\n"; - /* clang-format on */ + "Configure will be re-run and you may have to reset some variables.\n" + "The following variables have changed:\n"; for (auto i = argsSplit.begin(); i != argsSplit.end(); ++i) { SaveCacheEntry save; save.key = *i; @@ -2033,9 +2145,9 @@ int cmake::HandleDeleteCacheVariables(const std::string& var) i++; if (i != argsSplit.end()) { save.value = *i; - warning << *i << "\n"; + warning << *i << '\n'; } else { - warning << "\n"; + warning << '\n'; i -= 1; } cmValue existingValue = this->State->GetCacheEntryValue(save.key); @@ -2437,7 +2549,7 @@ void cmake::CreateDefaultGlobalGenerator() auto gen = this->EvaluateDefaultGlobalGenerator(); #if defined(_WIN32) && !defined(__CYGWIN__) && !defined(CMAKE_BOOT_MINGW) // This print could be unified for all platforms - std::cout << "-- Building for: " << gen->GetName() << "\n"; + std::cout << "-- Building for: " << gen->GetName() << '\n'; #endif this->SetGlobalGenerator(std::move(gen)); } @@ -2596,7 +2708,7 @@ int cmake::Generate() } this->GlobalGenerator->Generate(); if (!this->GraphVizFile.empty()) { - std::cout << "Generate graphviz: " << this->GraphVizFile << std::endl; + std::cout << "Generate graphviz: " << this->GraphVizFile << '\n'; this->GenerateGraphViz(this->GraphVizFile); } if (this->WarnUnusedCli) { @@ -2837,17 +2949,15 @@ void cmake::AppendGlobalGeneratorsDocumentation( std::vector<cmDocumentationEntry>& v) { const auto defaultGenerator = this->EvaluateDefaultGlobalGenerator(); - const std::string defaultName = defaultGenerator->GetName(); - bool foundDefaultOne = false; + const auto defaultName = defaultGenerator->GetName(); + auto foundDefaultOne = false; for (const auto& g : this->Generators) { - cmDocumentationEntry e; - g->GetDocumentation(e); - if (!foundDefaultOne && cmHasPrefix(e.Name, defaultName)) { - e.CustomNamePrefix = '*'; + v.emplace_back(g->GetDocumentation()); + if (!foundDefaultOne && cmHasPrefix(v.back().Name, defaultName)) { + v.back().CustomNamePrefix = '*'; foundDefaultOne = true; } - v.push_back(std::move(e)); } } @@ -2860,21 +2970,14 @@ void cmake::AppendExtraGeneratorsDocumentation( // Aliases: for (std::string const& a : eg->Aliases) { - cmDocumentationEntry e; - e.Name = a; - e.Brief = doc; - v.push_back(std::move(e)); + v.emplace_back(cmDocumentationEntry{ a, doc }); } // Full names: - const std::vector<std::string> generators = - eg->GetSupportedGlobalGenerators(); - for (std::string const& g : generators) { - cmDocumentationEntry e; - e.Name = - cmExternalMakefileProjectGenerator::CreateFullGeneratorName(g, name); - e.Brief = doc; - v.push_back(std::move(e)); + for (std::string const& g : eg->GetSupportedGlobalGenerators()) { + v.emplace_back(cmDocumentationEntry{ + cmExternalMakefileProjectGenerator::CreateFullGeneratorName(g, name), + doc }); } } } @@ -2893,7 +2996,7 @@ void cmake::PrintGeneratorList() cmDocumentation doc; auto generators = this->GetGeneratorsDocumentation(); doc.AppendSection("Generators", generators); - std::cerr << "\n"; + std::cerr << '\n'; doc.PrintDocumentation(cmDocumentation::ListGenerators, std::cerr); #endif } @@ -2945,7 +3048,7 @@ int cmake::CheckBuildSystem() if (verbose) { std::ostringstream msg; msg << "Re-run cmake missing file: " << this->CheckBuildSystemArgument - << "\n"; + << '\n'; cmSystemTools::Stdout(msg.str()); } return 1; @@ -2965,7 +3068,7 @@ int cmake::CheckBuildSystem() if (verbose) { std::ostringstream msg; msg << "Re-run cmake error reading : " << this->CheckBuildSystemArgument - << "\n"; + << '\n'; cmSystemTools::Stdout(msg.str()); } // There was an error reading the file. Just rerun. @@ -2996,9 +3099,8 @@ int cmake::CheckBuildSystem() for (std::string const& p : products) { if (!(cmSystemTools::FileExists(p) || cmSystemTools::FileIsSymlink(p))) { if (verbose) { - std::ostringstream msg; - msg << "Re-run cmake, missing byproduct: " << p << "\n"; - cmSystemTools::Stdout(msg.str()); + cmSystemTools::Stdout( + cmStrCat("Re-run cmake, missing byproduct: ", p, '\n')); } return 1; } @@ -3063,7 +3165,7 @@ int cmake::CheckBuildSystem() if (verbose) { std::ostringstream msg; msg << "Re-run cmake file: " << out_oldest - << " older than: " << dep_newest << "\n"; + << " older than: " << dep_newest << '\n'; cmSystemTools::Stdout(msg.str()); } return 1; @@ -3239,7 +3341,7 @@ int cmake::GetSystemInformation(std::vector<std::string>& args) // permissions are questionable or some other process has deleted the // directory std::cerr << "Failed to change to directory " << destPath << " : " - << std::strerror(workdir.GetLastResult()) << std::endl; + << std::strerror(workdir.GetLastResult()) << '\n'; return 1; } std::vector<std::string> args2; @@ -3276,96 +3378,6 @@ int cmake::GetSystemInformation(std::vector<std::string>& args) return 0; } -static bool cmakeCheckStampFile(const std::string& stampName) -{ - // The stamp file does not exist. Use the stamp dependencies to - // determine whether it is really out of date. This works in - // conjunction with cmLocalVisualStudio7Generator to avoid - // repeatedly re-running CMake when the user rebuilds the entire - // solution. - std::string stampDepends = cmStrCat(stampName, ".depend"); -#if defined(_WIN32) || defined(__CYGWIN__) - cmsys::ifstream fin(stampDepends.c_str(), std::ios::in | std::ios::binary); -#else - cmsys::ifstream fin(stampDepends.c_str()); -#endif - if (!fin) { - // The stamp dependencies file cannot be read. Just assume the - // build system is really out of date. - std::cout << "CMake is re-running because " << stampName - << " dependency file is missing.\n"; - return false; - } - - // Compare the stamp dependencies against the dependency file itself. - { - cmFileTimeCache ftc; - std::string dep; - while (cmSystemTools::GetLineFromStream(fin, dep)) { - int result; - if (!dep.empty() && dep[0] != '#' && - (!ftc.Compare(stampDepends, dep, &result) || result < 0)) { - // The stamp depends file is older than this dependency. The - // build system is really out of date. - std::cout << "CMake is re-running because " << stampName - << " is out-of-date.\n"; - std::cout << " the file '" << dep << "'\n"; - std::cout << " is newer than '" << stampDepends << "'\n"; - std::cout << " result='" << result << "'\n"; - return false; - } - } - } - - // The build system is up to date. The stamp file has been removed - // by the VS IDE due to a "rebuild" request. Restore it atomically. - std::ostringstream stampTempStream; - stampTempStream << stampName << ".tmp" << cmSystemTools::RandomSeed(); - std::string stampTemp = stampTempStream.str(); - { - // TODO: Teach cmGeneratedFileStream to use a random temp file (with - // multiple tries in unlikely case of conflict) and use that here. - cmsys::ofstream stamp(stampTemp.c_str()); - stamp << "# CMake generation timestamp file for this directory.\n"; - } - std::string err; - if (cmSystemTools::RenameFile(stampTemp, stampName, - cmSystemTools::Replace::Yes, &err) == - cmSystemTools::RenameResult::Success) { - // CMake does not need to re-run because the stamp file is up-to-date. - return true; - } - cmSystemTools::RemoveFile(stampTemp); - cmSystemTools::Error( - cmStrCat("Cannot restore timestamp \"", stampName, "\": ", err)); - return false; -} - -static bool cmakeCheckStampList(const std::string& stampList) -{ - // If the stamp list does not exist CMake must rerun to generate it. - if (!cmSystemTools::FileExists(stampList)) { - std::cout << "CMake is re-running because generate.stamp.list " - << "is missing.\n"; - return false; - } - cmsys::ifstream fin(stampList.c_str()); - if (!fin) { - std::cout << "CMake is re-running because generate.stamp.list " - << "could not be read.\n"; - return false; - } - - // Check each stamp. - std::string stampName; - while (cmSystemTools::GetLineFromStream(fin, stampName)) { - if (!cmakeCheckStampFile(stampName)) { - return false; - } - } - return true; -} - void cmake::IssueMessage(MessageType t, std::string const& text, cmListFileBacktrace const& backtrace) const { diff --git a/Source/cmake.h b/Source/cmake.h index 6b585a1..325c0c5 100644 --- a/Source/cmake.h +++ b/Source/cmake.h @@ -18,6 +18,7 @@ #include <cm/string_view> #include <cmext/string_view> +#include "cmDocumentationEntry.h" #include "cmGeneratedFileStream.h" #include "cmInstalledFile.h" #include "cmListFileCache.h" @@ -45,7 +46,6 @@ class cmMakefile; class cmMessenger; class cmVariableWatch; struct cmBuildOptions; -struct cmDocumentationEntry; /** \brief Represents a cmake invocation. * @@ -793,37 +793,10 @@ private: #if !defined(CMAKE_BOOTSTRAP) std::unique_ptr<cmMakefileProfilingData> ProfilingOutput; #endif -}; -#define CMAKE_STANDARD_OPTIONS_TABLE \ - { "-S <path-to-source>", "Explicitly specify a source directory." }, \ - { "-B <path-to-build>", "Explicitly specify a build directory." }, \ - { "-C <initial-cache>", "Pre-load a script to populate the cache." }, \ - { "-D <var>[:<type>]=<value>", "Create or update a cmake cache entry." }, \ - { "-U <globbing_expr>", "Remove matching entries from CMake cache." }, \ - { "-G <generator-name>", "Specify a build system generator." }, \ - { "-T <toolset-name>", \ - "Specify toolset name if supported by generator." }, \ - { "-A <platform-name>", \ - "Specify platform name if supported by generator." }, \ - { "--toolchain <file>", \ - "Specify toolchain file [CMAKE_TOOLCHAIN_FILE]." }, \ - { "--install-prefix <directory>", \ - "Specify install directory [CMAKE_INSTALL_PREFIX]." }, \ - { "-Wdev", "Enable developer warnings." }, \ - { "-Wno-dev", "Suppress developer warnings." }, \ - { "-Werror=dev", "Make developer warnings errors." }, \ - { "-Wno-error=dev", "Make developer warnings not errors." }, \ - { "-Wdeprecated", "Enable deprecation warnings." }, \ - { "-Wno-deprecated", "Suppress deprecation warnings." }, \ - { "-Werror=deprecated", \ - "Make deprecated macro and function warnings " \ - "errors." }, \ - { \ - "-Wno-error=deprecated", \ - "Make deprecated macro and function warnings " \ - "not errors." \ - } +public: + static cmDocumentationEntry CMAKE_STANDARD_OPTIONS_TABLE[18]; +}; #define FOR_EACH_C90_FEATURE(F) F(c_function_prototypes) diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx index 9f23667..a155787 100644 --- a/Source/cmakemain.cxx +++ b/Source/cmakemain.cxx @@ -24,7 +24,7 @@ #include "cmBuildOptions.h" #include "cmCommandLineArgument.h" #include "cmConsoleBuf.h" -#include "cmDocumentationEntry.h" // IWYU pragma: keep +#include "cmDocumentationEntry.h" #include "cmGlobalGenerator.h" #include "cmMakefile.h" #include "cmMessageMetadata.h" @@ -46,30 +46,28 @@ namespace { #ifndef CMAKE_BOOTSTRAP -const char* cmDocumentationName[][2] = { - { nullptr, " cmake - Cross-Platform Makefile Generator." }, - { nullptr, nullptr } +const cmDocumentationEntry cmDocumentationName = { + {}, + " cmake - Cross-Platform Makefile Generator." }; -const char* cmDocumentationUsage[][2] = { - { nullptr, +const cmDocumentationEntry cmDocumentationUsage[2] = { + { {}, " cmake [options] <path-to-source>\n" " cmake [options] <path-to-existing-build>\n" " cmake [options] -S <path-to-source> -B <path-to-build>" }, - { nullptr, + { {}, "Specify a source directory to (re-)generate a build system for " "it in the current working directory. Specify an existing build " - "directory to re-generate its build system." }, - { nullptr, nullptr } + "directory to re-generate its build system." } }; -const char* cmDocumentationUsageNote[][2] = { - { nullptr, "Run 'cmake --help' for more information." }, - { nullptr, nullptr } +const cmDocumentationEntry cmDocumentationUsageNote = { + {}, + "Run 'cmake --help' for more information." }; -const char* cmDocumentationOptions[][2] = { - CMAKE_STANDARD_OPTIONS_TABLE, +const cmDocumentationEntry cmDocumentationOptions[31] = { { "--preset <preset>,--preset=<preset>", "Specify a configure preset." }, { "--list-presets[=<type>]", "List available presets." }, { "-E", "CMake command mode." }, @@ -113,15 +111,12 @@ const char* cmDocumentationOptions[][2] = { { "--compile-no-warning-as-error", "Ignore COMPILE_WARNING_AS_ERROR property and " "CMAKE_COMPILE_WARNING_AS_ERROR variable." }, -# if !defined(CMAKE_BOOTSTRAP) { "--profiling-format=<fmt>", "Output data for profiling CMake scripts. Supported formats: " "google-trace" }, { "--profiling-output=<file>", "Select an output path for the profiling data enabled through " - "--profiling-format." }, -# endif - { nullptr, nullptr } + "--profiling-format." } }; #endif @@ -228,8 +223,9 @@ int do_cmake(int ac, char const* const* av) } doc.AppendSection("Generators", generators); doc.PrependSection("Options", cmDocumentationOptions); + doc.PrependSection("Options", cmake::CMAKE_STANDARD_OPTIONS_TABLE); - return doc.PrintRequestedDocumentation(std::cout) ? 0 : 1; + return !doc.PrintRequestedDocumentation(std::cout); } #else if (ac == 1) { diff --git a/Source/ctest.cxx b/Source/ctest.cxx index 363f473..fa38a65 100644 --- a/Source/ctest.cxx +++ b/Source/ctest.cxx @@ -11,21 +11,21 @@ #include "cmCTest.h" #include "cmConsoleBuf.h" #include "cmDocumentation.h" +#include "cmDocumentationEntry.h" #include "cmSystemTools.h" #include "CTest/cmCTestLaunch.h" #include "CTest/cmCTestScriptHandler.h" -static const char* cmDocumentationName[][2] = { - { nullptr, " ctest - Testing driver provided by CMake." }, - { nullptr, nullptr } +namespace { +const cmDocumentationEntry cmDocumentationName = { + {}, + " ctest - Testing driver provided by CMake." }; -static const char* cmDocumentationUsage[][2] = { { nullptr, - " ctest [options]" }, - { nullptr, nullptr } }; +const cmDocumentationEntry cmDocumentationUsage = { {}, " ctest [options]" }; -static const char* cmDocumentationOptions[][2] = { +const cmDocumentationEntry cmDocumentationOptions[74] = { { "--preset <preset>, --preset=<preset>", "Read arguments from a test preset." }, { "--list-presets", "List available test presets." }, @@ -155,9 +155,9 @@ static const char* cmDocumentationOptions[][2] = { { "--no-compress-output", "Do not compress test output when submitting." }, { "--print-labels", "Print all available test labels." }, { "--no-tests=<[error|ignore]>", - "Regard no tests found either as 'error' or 'ignore' it." }, - { nullptr, nullptr } + "Regard no tests found either as 'error' or 'ignore' it." } }; +} // anonymous namespace // this is a test driver program for cmCTest. int main(int argc, char const* const* argv) @@ -186,8 +186,7 @@ int main(int argc, char const* const* argv) if (cmSystemTools::GetCurrentWorkingDirectory().empty()) { cmCTestLog(&inst, ERROR_MESSAGE, - "Current working directory cannot be established." - << std::endl); + "Current working directory cannot be established.\n"); return 1; } @@ -199,10 +198,9 @@ int main(int argc, char const* const* argv) cmSystemTools::FileExists("DartTestfile.txt"))) { if (argc == 1) { cmCTestLog(&inst, ERROR_MESSAGE, - "*********************************" - << std::endl - << "No test configuration file found!" << std::endl - << "*********************************" << std::endl); + "*********************************\n" + "No test configuration file found!\n" + "*********************************\n"); } cmDocumentation doc; doc.addCTestStandardDocSections(); @@ -216,7 +214,7 @@ int main(int argc, char const* const* argv) doc.SetSection("Name", cmDocumentationName); doc.SetSection("Usage", cmDocumentationUsage); doc.PrependSection("Options", cmDocumentationOptions); - return doc.PrintRequestedDocumentation(std::cout) ? 0 : 1; + return !doc.PrintRequestedDocumentation(std::cout); } } diff --git a/Tests/CMakeTests/CMakeLists.txt b/Tests/CMakeTests/CMakeLists.txt index bd2dd7e..16e631b 100644 --- a/Tests/CMakeTests/CMakeLists.txt +++ b/Tests/CMakeTests/CMakeLists.txt @@ -32,16 +32,6 @@ AddCMakeTest(ProcessorCount "-DKWSYS_TEST_EXE=$<TARGET_FILE:cmsysTestsCxx>") AddCMakeTest(PushCheckState "") AddCMakeTest(While "") -AddCMakeTest(FileDownload "") -set_tests_properties(CMake.FileDownload PROPERTIES - PASS_REGULAR_EXPRESSION "file already exists with expected MD5 sum" - FAIL_REGULAR_EXPRESSION "Unexpected status|incorrectly interpreted" - ) -AddCMakeTest(FileDownloadBadHash "") -set_property(TEST CMake.FileDownloadBadHash PROPERTY - WILL_FAIL TRUE - ) - AddCMakeTest(FileUpload "") set(EndStuff_PreArgs diff --git a/Tests/CMakeTests/FileDownloadBadHashTest.cmake.in b/Tests/CMakeTests/FileDownloadBadHashTest.cmake.in deleted file mode 100644 index 64b45ed..0000000 --- a/Tests/CMakeTests/FileDownloadBadHashTest.cmake.in +++ /dev/null @@ -1,13 +0,0 @@ -if(NOT "@CMAKE_CURRENT_SOURCE_DIR@" MATCHES "^/") - set(slash /) -endif() -set(url "file://${slash}@CMAKE_CURRENT_SOURCE_DIR@/FileDownloadInput.png") -set(dir "@CMAKE_CURRENT_BINARY_DIR@/downloads") - -file(DOWNLOAD - ${url} - ${dir}/file3.png - TIMEOUT 2 - STATUS status - EXPECTED_HASH SHA1=5555555555555555555555555555555555555555 - ) diff --git a/Tests/CMakeTests/FileDownloadTest.cmake.in b/Tests/CMakeTests/FileDownloadTest.cmake.in deleted file mode 100644 index 255909d..0000000 --- a/Tests/CMakeTests/FileDownloadTest.cmake.in +++ /dev/null @@ -1,229 +0,0 @@ -# We do not contact any real URLs, but do try a bogus one. -# Remove any proxy configuration that may change behavior. -unset(ENV{http_proxy}) -unset(ENV{https_proxy}) - -set(timeout 4) - -if(NOT "@CMAKE_CURRENT_SOURCE_DIR@" MATCHES "^/") - set(slash /) -endif() -set(url "file://${slash}@CMAKE_CURRENT_SOURCE_DIR@/FileDownloadInput.png") -set(dir "@CMAKE_CURRENT_BINARY_DIR@/downloads") - -# Beware Windows asynchronous file/directory removal, rename and then -# remove the renamed dir so we can be certain the dir isn't there when -# we get to the file() commands below -if(EXISTS "${dir}") - file(RENAME ${dir} "${dir}_beingRemoved") - file(REMOVE_RECURSE "${dir}_beingRemoved") -endif() - -function(__reportIfWrongStatus statusPair expectedStatusCode) - list(GET statusPair 0 statusCode) - if(NOT statusCode EQUAL expectedStatusCode) - message(SEND_ERROR - "Unexpected status: ${statusCode}, expected: ${expectedStatusCode}") - endif() -endfunction() - -message(STATUS "FileDownload:1") -file(DOWNLOAD - ${url} - ${dir}/file1.png - TIMEOUT ${timeout} - STATUS status - ) -__reportIfWrongStatus("${status}" 0) - -message(STATUS "FileDownload:2") -file(DOWNLOAD - ${url} - ${dir}/file2.png - TIMEOUT ${timeout} - STATUS status - SHOW_PROGRESS - ) -__reportIfWrongStatus("${status}" 0) - -# Two calls in a row, exactly the same arguments. -# Since downloaded file should exist already for 2nd call, -# the 2nd call will short-circuit and return early... -# -if(EXISTS ${dir}/file3.png) - file(REMOVE ${dir}/file3.png) -endif() - -message(STATUS "FileDownload:3") -file(DOWNLOAD - ${url} - ${dir}/file3.png - TIMEOUT ${timeout} - STATUS status - EXPECTED_MD5 dbd330d52f4dbd60115d4191904ded92 - ) -__reportIfWrongStatus("${status}" 0) - -message(STATUS "FileDownload:4") -file(DOWNLOAD - ${url} - ${dir}/file3.png - TIMEOUT ${timeout} - STATUS status - EXPECTED_HASH SHA1=67eee17f79d9ac557284fc0b8ad19f25723fb578 - ) -__reportIfWrongStatus("${status}" 0) - -message(STATUS "FileDownload:5") -file(DOWNLOAD - ${url} - ${dir}/file3.png - TIMEOUT ${timeout} - STATUS status - EXPECTED_HASH SHA224=ba283726bbb602776818b463943189afd91836cb7ee5dd6e2c7b5ae4 - ) -__reportIfWrongStatus("${status}" 0) - -message(STATUS "FileDownload:6") -file(DOWNLOAD - ${url} - ${dir}/file3.png - TIMEOUT ${timeout} - STATUS status - EXPECTED_HASH SHA256=cf3334b1275071e1da6e8c396ccb72cf1b2388d8c937526f3af26230affb9423 - ) -__reportIfWrongStatus("${status}" 0) - -message(STATUS "FileDownload:7") -file(DOWNLOAD - ${url} - ${dir}/file3.png - TIMEOUT ${timeout} - STATUS status - EXPECTED_HASH SHA384=43a5d13978d97c660db44481aee0604cb4ff6ca0775cd5c2cd68cd8000e107e507c4caf6c228941231041e282ffb8950 - ) -__reportIfWrongStatus("${status}" 0) - -message(STATUS "FileDownload:8") -file(DOWNLOAD - ${url} - ${dir}/file3.png - TIMEOUT ${timeout} - STATUS status - EXPECTED_HASH SHA512=6984e0909a1018030ccaa418e3be1654223cdccff0fe6adc745f9aea7e377f178be53b9fc7d54a6f81c2b62ef9ddcd38ba1978fedf4c5e7139baaf355eefad5b - ) -__reportIfWrongStatus("${status}" 0) - -message(STATUS "FileDownload:9") -file(DOWNLOAD - ${url} - ${dir}/file3.png - TIMEOUT ${timeout} - STATUS status - EXPECTED_HASH MD5=dbd330d52f4dbd60115d4191904ded92 - ) -__reportIfWrongStatus("${status}" 0) - -message(STATUS "FileDownload:10") -file(DOWNLOAD - ${url} - ${dir}/file3.png - TIMEOUT ${timeout} - STATUS status - EXPECTED_MD5 dbd330d52f4dbd60115d4191904ded92 - ) -__reportIfWrongStatus("${status}" 0) -# Print status because we check its message too -message(STATUS "${status}") - -# do not use proxy for lookup of invalid site (DNS failure by proxy looks -# different than DNS failure without proxy) -set(ENV{no_proxy} "$ENV{no_proxy},badhostname.invalid") -message(STATUS "FileDownload:11") -file(DOWNLOAD - badhostname.invalid - ${dir}/file11.png - TIMEOUT 30 - STATUS status - ) -message(STATUS "${status}") -__reportIfWrongStatus("${status}" 6) # 6 corresponds to an unresolvable host name - -message(STATUS "FileDownload:12") -set(absFile "@CMAKE_CURRENT_BINARY_DIR@/file12.png") -if(EXISTS "${absFile}") - file(RENAME ${absFile} "${absFile}_beingRemoved") - file(REMOVE "${absFile}_beingRemoved") -endif() -file(DOWNLOAD - ${url} - file12.png - TIMEOUT ${timeout} - EXPECTED_MD5 dbd330d52f4dbd60115d4191904ded92 - STATUS status - ) -__reportIfWrongStatus("${status}" 0) -if(NOT EXISTS file12.png) - message(SEND_ERROR "file12.png not downloaded: ${status}") -endif() - -message(STATUS "FileDownload:13") -file(DOWNLOAD - ${url} - TIMEOUT ${timeout} - STATUS status - ) -__reportIfWrongStatus("${status}" 0) -if(EXISTS TIMEOUT) - file(REMOVE TIMEOUT) - message(SEND_ERROR "TIMEOUT argument was incorrectly interpreted as a filename") -endif() -message(STATUS "${status}") - -message(STATUS "FileDownload:14") -file(DOWNLOAD - ${url} - ${dir}/file14.bin - TIMEOUT ${timeout} - STATUS status - RANGE_START 0 - EXPECTED_MD5 dbd330d52f4dbd60115d4191904ded92 - ) -__reportIfWrongStatus("${status}" 0) - -message(STATUS "FileDownload:15") -file(DOWNLOAD - ${url} - ${dir}/file15.bin - TIMEOUT ${timeout} - STATUS status - RANGE_END 50 - EXPECTED_MD5 8592e5665b839b5d23825dc84c135b61 - ) -__reportIfWrongStatus("${status}" 0) - -message(STATUS "FileDownload:16") -file(DOWNLOAD - ${url} - ${dir}/file16.bin - TIMEOUT ${timeout} - STATUS status - RANGE_START 10 - RANGE_END 50 - EXPECTED_MD5 36cd52681e6c6c8fef85fcd9e86fc30d - ) -__reportIfWrongStatus("${status}" 0) - -message(STATUS "FileDownload:17") -file(DOWNLOAD - ${url} - ${dir}/file17.bin - TIMEOUT ${timeout} - STATUS status - RANGE_START 0 - RANGE_END 50 - RANGE_START 60 - RANGE_END 100 - EXPECTED_MD5 c5c9e74e82d493dd901eecccd659cebc - ) -__reportIfWrongStatus("${status}" 0) diff --git a/Tests/CMakeTests/FileDownloadInput.png b/Tests/CMakeTests/FileUploadInput.png Binary files differindex 9ab565a..9ab565a 100644 --- a/Tests/CMakeTests/FileDownloadInput.png +++ b/Tests/CMakeTests/FileUploadInput.png diff --git a/Tests/CMakeTests/FileUploadTest.cmake.in b/Tests/CMakeTests/FileUploadTest.cmake.in index 0e6f080..7725041 100644 --- a/Tests/CMakeTests/FileUploadTest.cmake.in +++ b/Tests/CMakeTests/FileUploadTest.cmake.in @@ -9,7 +9,7 @@ endif() file(MAKE_DIRECTORY "@CMAKE_CURRENT_BINARY_DIR@/uploads") -set(filename "@CMAKE_CURRENT_SOURCE_DIR@/FileDownloadInput.png") +set(filename "@CMAKE_CURRENT_SOURCE_DIR@/FileUploadInput.png") if(NOT "@CMAKE_CURRENT_BINARY_DIR@" MATCHES "^/") set(slash /) endif() diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index 1174d0d..0fe4919 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -466,6 +466,7 @@ add_RunCMake_test(ctest_fixtures) add_RunCMake_test(define_property) add_RunCMake_test(file -DCYGWIN=${CYGWIN} -DMSYS=${MSYS}) add_RunCMake_test(file-CHMOD -DMSYS=${MSYS}) +add_RunCMake_test(file-DOWNLOAD -DCMake_TEST_NO_NETWORK=${CMake_TEST_NO_NETWORK}) add_RunCMake_test(file-RPATH -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}) add_RunCMake_test(find_file) add_RunCMake_test(find_library -DCYGWIN=${CYGWIN} -DMSYS=${MSYS}) diff --git a/Tests/RunCMake/ExportImport/BuildInstallInterfaceGenex-export.cmake b/Tests/RunCMake/ExportImport/BuildInstallInterfaceGenex-export.cmake new file mode 100644 index 0000000..94076bb --- /dev/null +++ b/Tests/RunCMake/ExportImport/BuildInstallInterfaceGenex-export.cmake @@ -0,0 +1,14 @@ +enable_language(C) + +add_library(mainlib STATIC foo.c) +target_compile_definitions(mainlib INTERFACE + $<BUILD_LOCAL_INTERFACE:BUILD_LOCAL_INTERFACE> + $<BUILD_INTERFACE:BUILD_INTERFACE> + $<INSTALL_INTERFACE:INSTALL_INTERFACE> + ) +add_library(locallib STATIC locallib.c) +target_link_libraries(locallib PRIVATE mainlib) + +install(TARGETS mainlib EXPORT export) +install(EXPORT export DESTINATION lib/cmake/install FILE install-config.cmake NAMESPACE install::) +export(EXPORT export FILE build-config.cmake NAMESPACE build::) diff --git a/Tests/RunCMake/ExportImport/BuildInstallInterfaceGenex-import.cmake b/Tests/RunCMake/ExportImport/BuildInstallInterfaceGenex-import.cmake new file mode 100644 index 0000000..3fe5fae --- /dev/null +++ b/Tests/RunCMake/ExportImport/BuildInstallInterfaceGenex-import.cmake @@ -0,0 +1,9 @@ +enable_language(C) + +find_package(build REQUIRED) +find_package(install REQUIRED) + +add_library(buildlib STATIC buildlib.c) +target_link_libraries(buildlib PRIVATE build::mainlib) +add_library(installlib STATIC installlib.c) +target_link_libraries(installlib PRIVATE install::mainlib) diff --git a/Tests/RunCMake/ExportImport/RunCMakeTest.cmake b/Tests/RunCMake/ExportImport/RunCMakeTest.cmake index d07fca2..b730047 100644 --- a/Tests/RunCMake/ExportImport/RunCMakeTest.cmake +++ b/Tests/RunCMake/ExportImport/RunCMakeTest.cmake @@ -22,3 +22,28 @@ function(run_ExportImport_test case) endfunction() run_ExportImport_test(SharedDep) + +function(run_ExportImportBuildInstall_test case) + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${case}-export-build) + set(CMAKE_INSTALL_PREFIX ${RunCMake_TEST_BINARY_DIR}/root) + if (NOT RunCMake_GENERATOR_IS_MULTI_CONFIG) + set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Debug) + endif() + run_cmake(${case}-export) + unset(RunCMake_TEST_OPTIONS) + set(RunCMake_TEST_NO_CLEAN 1) + run_cmake_command(${case}-export-build ${CMAKE_COMMAND} --build . --config Debug) + run_cmake_command(${case}-export-install ${CMAKE_COMMAND} -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} -DBUILD_TYPE=Debug -P cmake_install.cmake) + unset(RunCMake_TEST_NO_CLEAN) + + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${case}-import-build) + run_cmake_with_options(${case}-import + -Dbuild_DIR=${RunCMake_BINARY_DIR}/${case}-export-build + -Dinstall_DIR=${CMAKE_INSTALL_PREFIX}/lib/cmake/install + ) + set(RunCMake_TEST_NO_CLEAN 1) + run_cmake_command(${case}-import-build ${CMAKE_COMMAND} --build . --config Debug) + unset(RunCMake_TEST_NO_CLEAN) +endfunction() + +run_ExportImportBuildInstall_test(BuildInstallInterfaceGenex) diff --git a/Tests/RunCMake/ExportImport/buildlib.c b/Tests/RunCMake/ExportImport/buildlib.c new file mode 100644 index 0000000..ac19310 --- /dev/null +++ b/Tests/RunCMake/ExportImport/buildlib.c @@ -0,0 +1,8 @@ +#if !(!defined(BUILD_LOCAL_INTERFACE) && defined(BUILD_INTERFACE) && \ + !defined(INSTALL_INTERFACE)) +# error "Incorrect compile definitions" +#endif + +void buildlib(void) +{ +} diff --git a/Tests/RunCMake/ExportImport/installlib.c b/Tests/RunCMake/ExportImport/installlib.c new file mode 100644 index 0000000..00d503c --- /dev/null +++ b/Tests/RunCMake/ExportImport/installlib.c @@ -0,0 +1,8 @@ +#if !(!defined(BUILD_LOCAL_INTERFACE) && !defined(BUILD_INTERFACE) && \ + defined(INSTALL_INTERFACE)) +# error "Incorrect compile definitions" +#endif + +void installlib(void) +{ +} diff --git a/Tests/RunCMake/ExportImport/locallib.c b/Tests/RunCMake/ExportImport/locallib.c new file mode 100644 index 0000000..f9e3d8d --- /dev/null +++ b/Tests/RunCMake/ExportImport/locallib.c @@ -0,0 +1,8 @@ +#if !(defined(BUILD_LOCAL_INTERFACE) && defined(BUILD_INTERFACE) && \ + !defined(INSTALL_INTERFACE)) +# error "Incorrect compile definitions" +#endif + +void locallib(void) +{ +} diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/RunCMakeTest.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/RunCMakeTest.cmake index ac0843e..b613ad1 100644 --- a/Tests/RunCMake/GenEx-TARGET_PROPERTY/RunCMakeTest.cmake +++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/RunCMakeTest.cmake @@ -13,3 +13,10 @@ run_cmake(LinkImplementationCycle5) run_cmake(LinkImplementationCycle6) run_cmake(LOCATION) run_cmake(SOURCES) + +block() + run_cmake(Scope) + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/Scope-build) + set(RunCMake_TEST_NO_CLEAN 1) + run_cmake_command(Scope-build ${CMAKE_COMMAND} --build . --config Debug) +endblock() diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/Scope-build-stdout.txt b/Tests/RunCMake/GenEx-TARGET_PROPERTY/Scope-build-stdout.txt new file mode 100644 index 0000000..fefad22 --- /dev/null +++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/Scope-build-stdout.txt @@ -0,0 +1,6 @@ +.*iface scope1: 'SCOPED_A_1;SCOPED_B_1' +.*iface scope2: 'SCOPED_A_2' +.*iface scope2 in scope1: 'SCOPED_A_2' +.*custom scope1: 'SCOPED_A_1;SCOPED_B_1' +.*custom scope2: 'SCOPED_A_2' +.*custom scope2 in scope1: 'SCOPED_A_1' diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/Scope.c b/Tests/RunCMake/GenEx-TARGET_PROPERTY/Scope.c new file mode 100644 index 0000000..a4bec6f --- /dev/null +++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/Scope.c @@ -0,0 +1,12 @@ +#ifndef SCOPED_A_1 +# error "SCOPED_A_1 not defined" +#endif +#ifndef SCOPED_B_1 +# error "SCOPED_B_1 not defined" +#endif +#ifndef SCOPED_A_2 +# error "SCOPED_A_2 not defined" +#endif +void Scope(void) +{ +} diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/Scope.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/Scope.cmake new file mode 100644 index 0000000..48a878a --- /dev/null +++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/Scope.cmake @@ -0,0 +1,19 @@ +enable_language(C) + +add_subdirectory(Scope1) +add_subdirectory(Scope2) + +add_library(Scope Scope.c) +target_link_libraries(Scope PRIVATE + scope1_iface + scope2_iface + ) + +add_custom_target(Custom ALL VERBATIM + COMMAND ${CMAKE_COMMAND} -E echo "iface scope1: '$<TARGET_PROPERTY:scope1_iface,INTERFACE_COMPILE_DEFINITIONS>'" + COMMAND ${CMAKE_COMMAND} -E echo "iface scope2: '$<TARGET_PROPERTY:scope2_iface,INTERFACE_COMPILE_DEFINITIONS>'" + COMMAND ${CMAKE_COMMAND} -E echo "iface scope2 in scope1: '$<TARGET_GENEX_EVAL:scope1_iface,$<TARGET_PROPERTY:scope2_iface,INTERFACE_COMPILE_DEFINITIONS>>'" + COMMAND ${CMAKE_COMMAND} -E echo "custom scope1: '$<TARGET_GENEX_EVAL:scope1_iface,$<TARGET_PROPERTY:scope1_iface,CUSTOM_PROP>>'" + COMMAND ${CMAKE_COMMAND} -E echo "custom scope2: '$<TARGET_GENEX_EVAL:scope2_iface,$<TARGET_PROPERTY:scope2_iface,CUSTOM_PROP>>'" + COMMAND ${CMAKE_COMMAND} -E echo "custom scope2 in scope1: '$<TARGET_GENEX_EVAL:scope1_iface,$<TARGET_PROPERTY:scope2_iface,CUSTOM_PROP>>'" + ) diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/Scope1/CMakeLists.txt b/Tests/RunCMake/GenEx-TARGET_PROPERTY/Scope1/CMakeLists.txt new file mode 100644 index 0000000..d546267 --- /dev/null +++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/Scope1/CMakeLists.txt @@ -0,0 +1,15 @@ +add_library(scopedA INTERFACE IMPORTED) +set_property(TARGET scopedA PROPERTY INTERFACE_COMPILE_DEFINITIONS "SCOPED_A_1") + +add_library(scopedB INTERFACE IMPORTED) +set_property(TARGET scopedB PROPERTY INTERFACE_COMPILE_DEFINITIONS "SCOPED_B_1") + +add_library(scope1_iface INTERFACE) +set_property(TARGET scope1_iface PROPERTY INTERFACE_COMPILE_DEFINITIONS + "$<TARGET_PROPERTY:scopedA,INTERFACE_COMPILE_DEFINITIONS>" + "$<TARGET_PROPERTY:scopedB,INTERFACE_COMPILE_DEFINITIONS>" + ) +set_property(TARGET scope1_iface PROPERTY CUSTOM_PROP + "$<TARGET_PROPERTY:scopedA,INTERFACE_COMPILE_DEFINITIONS>" + "$<TARGET_PROPERTY:scopedB,INTERFACE_COMPILE_DEFINITIONS>" + ) diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/Scope2/CMakeLists.txt b/Tests/RunCMake/GenEx-TARGET_PROPERTY/Scope2/CMakeLists.txt new file mode 100644 index 0000000..a6d7e6b --- /dev/null +++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/Scope2/CMakeLists.txt @@ -0,0 +1,10 @@ +add_library(scopedA INTERFACE IMPORTED) +set_property(TARGET scopedA PROPERTY INTERFACE_COMPILE_DEFINITIONS "SCOPED_A_2") + +add_library(scope2_iface INTERFACE) +set_property(TARGET scope2_iface PROPERTY INTERFACE_COMPILE_DEFINITIONS + "$<TARGET_PROPERTY:scopedA,INTERFACE_COMPILE_DEFINITIONS>" + ) +set_property(TARGET scope2_iface PROPERTY CUSTOM_PROP + "$<TARGET_PROPERTY:scopedA,INTERFACE_COMPILE_DEFINITIONS>" + ) diff --git a/Tests/RunCMake/Swift/NoWorkToDo-nowork-stdout.txt b/Tests/RunCMake/Swift/NoWorkToDo-nowork-stdout.txt new file mode 100644 index 0000000..60a9228 --- /dev/null +++ b/Tests/RunCMake/Swift/NoWorkToDo-nowork-stdout.txt @@ -0,0 +1 @@ +^ninja: no work to do diff --git a/Tests/RunCMake/Swift/NoWorkToDo.cmake b/Tests/RunCMake/Swift/NoWorkToDo.cmake new file mode 100644 index 0000000..e86a861 --- /dev/null +++ b/Tests/RunCMake/Swift/NoWorkToDo.cmake @@ -0,0 +1,2 @@ +enable_language(Swift) +add_executable(hello hello.swift) diff --git a/Tests/RunCMake/Swift/RunCMakeTest.cmake b/Tests/RunCMake/Swift/RunCMakeTest.cmake index 21d5a25..7f4464d 100644 --- a/Tests/RunCMake/Swift/RunCMakeTest.cmake +++ b/Tests/RunCMake/Swift/RunCMakeTest.cmake @@ -14,6 +14,16 @@ elseif(RunCMake_GENERATOR STREQUAL Ninja) run_cmake(SwiftMultiArch) unset(RunCMake_TEST_OPTIONS) endif() + + # Test that a second build with no changes does nothing. + block() + run_cmake(NoWorkToDo) + set(RunCMake_TEST_NO_CLEAN 1) + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/NoWorkToDo-build) + set(RunCMake_TEST_OUTPUT_MERGE 1) + run_cmake_command(NoWorkToDo-build ${CMAKE_COMMAND} --build .) + run_cmake_command(NoWorkToDo-nowork ${CMAKE_COMMAND} --build . -- -d explain) + endblock() endif() elseif(RunCMake_GENERATOR STREQUAL "Ninja Multi-Config") if(CMAKE_Swift_COMPILER) diff --git a/Tests/RunCMake/file/DOWNLOAD-unused-argument.txt b/Tests/RunCMake/Swift/hello.swift index e69de29..e69de29 100644 --- a/Tests/RunCMake/file/DOWNLOAD-unused-argument.txt +++ b/Tests/RunCMake/Swift/hello.swift diff --git a/Tests/RunCMake/file-DOWNLOAD/CMakeLists.txt b/Tests/RunCMake/file-DOWNLOAD/CMakeLists.txt new file mode 100644 index 0000000..9a66cde --- /dev/null +++ b/Tests/RunCMake/file-DOWNLOAD/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 3.13) +project(${RunCMake_TEST} NONE) +include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/file-DOWNLOAD/EXPECTED_HASH-stdout.txt b/Tests/RunCMake/file-DOWNLOAD/EXPECTED_HASH-stdout.txt new file mode 100644 index 0000000..bd1727a --- /dev/null +++ b/Tests/RunCMake/file-DOWNLOAD/EXPECTED_HASH-stdout.txt @@ -0,0 +1,8 @@ +-- status='0;"No error"' +-- status='0;"skipping download as file already exists with expected MD5 sum"' +-- status='0;"skipping download as file already exists with expected MD5 hash"' +-- status='0;"skipping download as file already exists with expected SHA1 hash"' +-- status='0;"skipping download as file already exists with expected SHA224 hash"' +-- status='0;"skipping download as file already exists with expected SHA256 hash"' +-- status='0;"skipping download as file already exists with expected SHA384 hash"' +-- status='0;"skipping download as file already exists with expected SHA512 hash"' diff --git a/Tests/RunCMake/file-DOWNLOAD/EXPECTED_HASH.cmake b/Tests/RunCMake/file-DOWNLOAD/EXPECTED_HASH.cmake new file mode 100644 index 0000000..dc7f8ff --- /dev/null +++ b/Tests/RunCMake/file-DOWNLOAD/EXPECTED_HASH.cmake @@ -0,0 +1,13 @@ +include(common.cmake) + +# Actually download the file and verify its hash. +file_download(EXPECTED_MD5 dbd330d52f4dbd60115d4191904ded92) + +# Verify that the local file already exists with expected hash. +file_download(EXPECTED_MD5 dbd330d52f4dbd60115d4191904ded92) +file_download(EXPECTED_HASH MD5=dbd330d52f4dbd60115d4191904ded92) +file_download(EXPECTED_HASH SHA1=67eee17f79d9ac557284fc0b8ad19f25723fb578) +file_download(EXPECTED_HASH SHA224=ba283726bbb602776818b463943189afd91836cb7ee5dd6e2c7b5ae4) +file_download(EXPECTED_HASH SHA256=cf3334b1275071e1da6e8c396ccb72cf1b2388d8c937526f3af26230affb9423) +file_download(EXPECTED_HASH SHA384=43a5d13978d97c660db44481aee0604cb4ff6ca0775cd5c2cd68cd8000e107e507c4caf6c228941231041e282ffb8950) +file_download(EXPECTED_HASH SHA512=6984e0909a1018030ccaa418e3be1654223cdccff0fe6adc745f9aea7e377f178be53b9fc7d54a6f81c2b62ef9ddcd38ba1978fedf4c5e7139baaf355eefad5b) diff --git a/Tests/RunCMake/file-DOWNLOAD/RunCMakeTest.cmake b/Tests/RunCMake/file-DOWNLOAD/RunCMakeTest.cmake new file mode 100644 index 0000000..565f440 --- /dev/null +++ b/Tests/RunCMake/file-DOWNLOAD/RunCMakeTest.cmake @@ -0,0 +1,26 @@ +include(RunCMake) + +# We do not contact any real URLs, but do try a bogus one. +# Remove any proxy configuration that may change behavior. +unset(ENV{http_proxy}) +unset(ENV{https_proxy}) + +run_cmake(hash-mismatch) +run_cmake(unused-argument) +run_cmake(httpheader-not-set) +run_cmake(netrc-bad) +run_cmake(tls-cainfo-not-set) +run_cmake(tls-verify-not-set) +run_cmake(pass-not-set) +run_cmake(no-save-hash) + +run_cmake(basic) +run_cmake(EXPECTED_HASH) +run_cmake(file-without-path) +run_cmake(no-file) +run_cmake(range) +run_cmake(SHOW_PROGRESS) + +if(NOT CMake_TEST_NO_NETWORK) + run_cmake(bad-hostname) +endif() diff --git a/Tests/RunCMake/file-DOWNLOAD/SHOW_PROGRESS-stdout.txt b/Tests/RunCMake/file-DOWNLOAD/SHOW_PROGRESS-stdout.txt new file mode 100644 index 0000000..e0a4982 --- /dev/null +++ b/Tests/RunCMake/file-DOWNLOAD/SHOW_PROGRESS-stdout.txt @@ -0,0 +1,2 @@ +-- \[download 100% complete\] +-- status='0;"No error"' diff --git a/Tests/RunCMake/file-DOWNLOAD/SHOW_PROGRESS.cmake b/Tests/RunCMake/file-DOWNLOAD/SHOW_PROGRESS.cmake new file mode 100644 index 0000000..ccabced --- /dev/null +++ b/Tests/RunCMake/file-DOWNLOAD/SHOW_PROGRESS.cmake @@ -0,0 +1,3 @@ +include(common.cmake) + +file_download(SHOW_PROGRESS) diff --git a/Tests/RunCMake/file-DOWNLOAD/bad-hostname-stdout.txt b/Tests/RunCMake/file-DOWNLOAD/bad-hostname-stdout.txt new file mode 100644 index 0000000..12278e0 --- /dev/null +++ b/Tests/RunCMake/file-DOWNLOAD/bad-hostname-stdout.txt @@ -0,0 +1 @@ +-- status='6;"Couldn't resolve host name"' diff --git a/Tests/RunCMake/file-DOWNLOAD/bad-hostname.cmake b/Tests/RunCMake/file-DOWNLOAD/bad-hostname.cmake new file mode 100644 index 0000000..d3b7a28 --- /dev/null +++ b/Tests/RunCMake/file-DOWNLOAD/bad-hostname.cmake @@ -0,0 +1,9 @@ +include(common.cmake) + +# Do not use any proxy for lookup of an invalid site. +# DNS failure by proxy looks different than DNS failure without proxy. +set(ENV{no_proxy} "$ENV{no_proxy},badhostname.invalid") + +set(url "badhostname.invalid") + +file_download() diff --git a/Tests/RunCMake/file-DOWNLOAD/basic-stdout.txt b/Tests/RunCMake/file-DOWNLOAD/basic-stdout.txt new file mode 100644 index 0000000..701e995 --- /dev/null +++ b/Tests/RunCMake/file-DOWNLOAD/basic-stdout.txt @@ -0,0 +1 @@ +-- status='0;"No error"' diff --git a/Tests/RunCMake/file-DOWNLOAD/basic.cmake b/Tests/RunCMake/file-DOWNLOAD/basic.cmake new file mode 100644 index 0000000..1fd931c --- /dev/null +++ b/Tests/RunCMake/file-DOWNLOAD/basic.cmake @@ -0,0 +1,3 @@ +include(common.cmake) + +file_download() diff --git a/Tests/RunCMake/file-DOWNLOAD/common.cmake b/Tests/RunCMake/file-DOWNLOAD/common.cmake new file mode 100644 index 0000000..6aa2fe6 --- /dev/null +++ b/Tests/RunCMake/file-DOWNLOAD/common.cmake @@ -0,0 +1,15 @@ +if(NOT "${CMAKE_CURRENT_SOURCE_DIR}" MATCHES "^/") + set(slash /) +endif() +set(url "file://${slash}${CMAKE_CURRENT_SOURCE_DIR}/input.png") +set(file ${CMAKE_CURRENT_BINARY_DIR}/output.png) + +function(file_download) + file(DOWNLOAD "${url}" + ${file} # leave unquoted + TIMEOUT 30 + STATUS status + ${ARGN} + ) + message(STATUS "status='${status}'") +endfunction() diff --git a/Tests/RunCMake/file-DOWNLOAD/file-without-path-stdout.txt b/Tests/RunCMake/file-DOWNLOAD/file-without-path-stdout.txt new file mode 100644 index 0000000..701e995 --- /dev/null +++ b/Tests/RunCMake/file-DOWNLOAD/file-without-path-stdout.txt @@ -0,0 +1 @@ +-- status='0;"No error"' diff --git a/Tests/RunCMake/file-DOWNLOAD/file-without-path.cmake b/Tests/RunCMake/file-DOWNLOAD/file-without-path.cmake new file mode 100644 index 0000000..a628423 --- /dev/null +++ b/Tests/RunCMake/file-DOWNLOAD/file-without-path.cmake @@ -0,0 +1,10 @@ +include(common.cmake) + +set(file_orig "${file}") +cmake_path(GET file_orig FILENAME file) + +file_download() + +if(NOT EXISTS "${file_orig}") + message(FATAL_ERROR "file not downloaded to expected path:\n ${file_orig}") +endif() diff --git a/Tests/RunCMake/file/DOWNLOAD-tls-verify-not-set-result.txt b/Tests/RunCMake/file-DOWNLOAD/hash-mismatch-result.txt index d00491f..d00491f 100644 --- a/Tests/RunCMake/file/DOWNLOAD-tls-verify-not-set-result.txt +++ b/Tests/RunCMake/file-DOWNLOAD/hash-mismatch-result.txt diff --git a/Tests/RunCMake/file-DOWNLOAD/hash-mismatch-stderr.txt b/Tests/RunCMake/file-DOWNLOAD/hash-mismatch-stderr.txt new file mode 100644 index 0000000..6682794 --- /dev/null +++ b/Tests/RunCMake/file-DOWNLOAD/hash-mismatch-stderr.txt @@ -0,0 +1,11 @@ +^CMake Error at hash-mismatch.cmake:[0-9]+ \(file\): + file DOWNLOAD HASH mismatch + + for file: \[.*/Tests/RunCMake/file-DOWNLOAD/hash-mismatch-build/output.png\] + expected hash: \[0123456789abcdef0123456789abcdef01234567\] + actual hash: \[67eee17f79d9ac557284fc0b8ad19f25723fb578\] + +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) ++ +status='1;HASH mismatch: expected: 0123456789abcdef0123456789abcdef01234567 actual: 67eee17f79d9ac557284fc0b8ad19f25723fb578'$ diff --git a/Tests/RunCMake/file-DOWNLOAD/hash-mismatch.cmake b/Tests/RunCMake/file-DOWNLOAD/hash-mismatch.cmake new file mode 100644 index 0000000..e3f91e3 --- /dev/null +++ b/Tests/RunCMake/file-DOWNLOAD/hash-mismatch.cmake @@ -0,0 +1,8 @@ +include(common.cmake) + +file(DOWNLOAD ${url} ${file} + EXPECTED_HASH SHA1=0123456789abcdef0123456789abcdef01234567 + TIMEOUT 30 + STATUS status + ) +message("status='${status}'") diff --git a/Tests/RunCMake/file/DOWNLOAD-tls-cainfo-not-set-result.txt b/Tests/RunCMake/file-DOWNLOAD/httpheader-not-set-result.txt index d00491f..d00491f 100644 --- a/Tests/RunCMake/file/DOWNLOAD-tls-cainfo-not-set-result.txt +++ b/Tests/RunCMake/file-DOWNLOAD/httpheader-not-set-result.txt diff --git a/Tests/RunCMake/file/DOWNLOAD-httpheader-not-set-stderr.txt b/Tests/RunCMake/file-DOWNLOAD/httpheader-not-set-stderr.txt index 247923b..3ac5082 100644 --- a/Tests/RunCMake/file/DOWNLOAD-httpheader-not-set-stderr.txt +++ b/Tests/RunCMake/file-DOWNLOAD/httpheader-not-set-stderr.txt @@ -1,4 +1,4 @@ -^CMake Error at DOWNLOAD-httpheader-not-set.cmake:[0-9]+ \(file\): +^CMake Error at httpheader-not-set.cmake:[0-9]+ \(file\): file DOWNLOAD missing string for HTTPHEADER. Call Stack \(most recent call first\): CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/file/DOWNLOAD-httpheader-not-set.cmake b/Tests/RunCMake/file-DOWNLOAD/httpheader-not-set.cmake index 6efc958..6efc958 100644 --- a/Tests/RunCMake/file/DOWNLOAD-httpheader-not-set.cmake +++ b/Tests/RunCMake/file-DOWNLOAD/httpheader-not-set.cmake diff --git a/Tests/RunCMake/file-DOWNLOAD/input.png b/Tests/RunCMake/file-DOWNLOAD/input.png Binary files differnew file mode 100644 index 0000000..9ab565a --- /dev/null +++ b/Tests/RunCMake/file-DOWNLOAD/input.png diff --git a/Tests/RunCMake/file/DOWNLOAD-pass-not-set-result.txt b/Tests/RunCMake/file-DOWNLOAD/netrc-bad-result.txt index d00491f..d00491f 100644 --- a/Tests/RunCMake/file/DOWNLOAD-pass-not-set-result.txt +++ b/Tests/RunCMake/file-DOWNLOAD/netrc-bad-result.txt diff --git a/Tests/RunCMake/file/DOWNLOAD-netrc-bad-stderr.txt b/Tests/RunCMake/file-DOWNLOAD/netrc-bad-stderr.txt index 96ce62a..61d7c99 100644 --- a/Tests/RunCMake/file/DOWNLOAD-netrc-bad-stderr.txt +++ b/Tests/RunCMake/file-DOWNLOAD/netrc-bad-stderr.txt @@ -1,19 +1,19 @@ -^CMake Error at DOWNLOAD-netrc-bad\.cmake:[0-9]+ \(file\): +^CMake Error at netrc-bad\.cmake:[0-9]+ \(file\): file DOWNLOAD missing level value for NETRC\. Call Stack \(most recent call first\): CMakeLists\.txt:[0-9]+ \(include\) + -CMake Error at DOWNLOAD-netrc-bad\.cmake:[0-9]+ \(file\): +CMake Error at netrc-bad\.cmake:[0-9]+ \(file\): file DOWNLOAD missing file value for NETRC_FILE\. Call Stack \(most recent call first\): CMakeLists\.txt:[0-9]+ \(include\) + -CMake Error at DOWNLOAD-netrc-bad\.cmake:[0-9]+ \(file\): +CMake Error at netrc-bad\.cmake:[0-9]+ \(file\): file NETRC accepts OPTIONAL, IGNORED or REQUIRED but got: INVALID Call Stack \(most recent call first\): CMakeLists\.txt:[0-9]+ \(include\) + -CMake Error at DOWNLOAD-netrc-bad\.cmake:[0-9]+ \(file\): +CMake Error at netrc-bad\.cmake:[0-9]+ \(file\): file NETRC accepts OPTIONAL, IGNORED or REQUIRED but got: FALSE Call Stack \(most recent call first\): CMakeLists\.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/file/DOWNLOAD-netrc-bad.cmake b/Tests/RunCMake/file-DOWNLOAD/netrc-bad.cmake index 6a62df9..c62238a 100644 --- a/Tests/RunCMake/file/DOWNLOAD-netrc-bad.cmake +++ b/Tests/RunCMake/file-DOWNLOAD/netrc-bad.cmake @@ -5,11 +5,11 @@ file(DOWNLOAD "" "" NETRC) file(DOWNLOAD "" "" NETRC_FILE) set(CMAKE_NETRC FALSE) file(DOWNLOAD - "file://${slash}${CMAKE_CURRENT_SOURCE_DIR}/DOWNLOAD-netrc-bad.txt" + "file://${slash}${CMAKE_CURRENT_SOURCE_DIR}/netrc-bad.txt" "${CMAKE_CURRENT_BINARY_DIR}/netrc-bad.txt" NETRC INVALID ) file(DOWNLOAD - "file://${slash}${CMAKE_CURRENT_SOURCE_DIR}/DOWNLOAD-netrc-bad.txt" + "file://${slash}${CMAKE_CURRENT_SOURCE_DIR}/netrc-bad.txt" "${CMAKE_CURRENT_BINARY_DIR}/netrc-bad.txt" ) diff --git a/Tests/RunCMake/file/DOWNLOAD-unused-argument-result.txt b/Tests/RunCMake/file-DOWNLOAD/netrc-bad.txt index e69de29..e69de29 100644 --- a/Tests/RunCMake/file/DOWNLOAD-unused-argument-result.txt +++ b/Tests/RunCMake/file-DOWNLOAD/netrc-bad.txt diff --git a/Tests/RunCMake/file-DOWNLOAD/no-file-arg.cmake b/Tests/RunCMake/file-DOWNLOAD/no-file-arg.cmake new file mode 100644 index 0000000..6520940 --- /dev/null +++ b/Tests/RunCMake/file-DOWNLOAD/no-file-arg.cmake @@ -0,0 +1,11 @@ +include(common.cmake) + +set(file "") + +file_download() + +set(file "${CMAKE_CURRENT_BINARY_DIR}/input.png") + +if(NOT EXISTS "${file}") + message(FATAL_ERROR "file not downloaded to expected path:\n ${file}") +endif() diff --git a/Tests/RunCMake/file-DOWNLOAD/no-file-stdout.txt b/Tests/RunCMake/file-DOWNLOAD/no-file-stdout.txt new file mode 100644 index 0000000..701e995 --- /dev/null +++ b/Tests/RunCMake/file-DOWNLOAD/no-file-stdout.txt @@ -0,0 +1 @@ +-- status='0;"No error"' diff --git a/Tests/RunCMake/file-DOWNLOAD/no-file.cmake b/Tests/RunCMake/file-DOWNLOAD/no-file.cmake new file mode 100644 index 0000000..dc234b2 --- /dev/null +++ b/Tests/RunCMake/file-DOWNLOAD/no-file.cmake @@ -0,0 +1,11 @@ +include(common.cmake) + +# Test downloading without saving to a file. +set(file "") +file_download() + +foreach(name input.png output.png TIMEOUT) + if(EXISTS "${CMAKE_CURRENT_BINARY_DIR}/${name}") + message(FATAL_ERROR "file incorrectly saved to:\n ${CMAKE_CURRENT_BINARY_DIR}/${name}") + endif() +endforeach() diff --git a/Tests/RunCMake/file/DOWNLOAD-no-save-hash-result.txt b/Tests/RunCMake/file-DOWNLOAD/no-save-hash-result.txt index d00491f..d00491f 100644 --- a/Tests/RunCMake/file/DOWNLOAD-no-save-hash-result.txt +++ b/Tests/RunCMake/file-DOWNLOAD/no-save-hash-result.txt diff --git a/Tests/RunCMake/file/DOWNLOAD-no-save-hash-stderr.txt b/Tests/RunCMake/file-DOWNLOAD/no-save-hash-stderr.txt index b0f0d19..8f2f885 100644 --- a/Tests/RunCMake/file/DOWNLOAD-no-save-hash-stderr.txt +++ b/Tests/RunCMake/file-DOWNLOAD/no-save-hash-stderr.txt @@ -1,4 +1,5 @@ -^CMake Error at DOWNLOAD-no-save-hash\.cmake:[0-9]+ \(file\): +^CMake Error at common\.cmake:[0-9]+ \(file\): file DOWNLOAD cannot calculate hash if file is not saved\. Call Stack \(most recent call first\): + no-save-hash.cmake:[0-9]+ \(file_download\) CMakeLists\.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/file-DOWNLOAD/no-save-hash.cmake b/Tests/RunCMake/file-DOWNLOAD/no-save-hash.cmake new file mode 100644 index 0000000..7fdc397 --- /dev/null +++ b/Tests/RunCMake/file-DOWNLOAD/no-save-hash.cmake @@ -0,0 +1,5 @@ +include(common.cmake) + +# Test downloading without saving to a file. +set(file "") +file_download(EXPECTED_HASH MD5=55555555555555555555555555555555) diff --git a/Tests/RunCMake/file/DOWNLOAD-no-save-hash.txt b/Tests/RunCMake/file-DOWNLOAD/no-save-hash.txt index e69de29..e69de29 100644 --- a/Tests/RunCMake/file/DOWNLOAD-no-save-hash.txt +++ b/Tests/RunCMake/file-DOWNLOAD/no-save-hash.txt diff --git a/Tests/RunCMake/file/DOWNLOAD-netrc-bad-result.txt b/Tests/RunCMake/file-DOWNLOAD/pass-not-set-result.txt index d00491f..d00491f 100644 --- a/Tests/RunCMake/file/DOWNLOAD-netrc-bad-result.txt +++ b/Tests/RunCMake/file-DOWNLOAD/pass-not-set-result.txt diff --git a/Tests/RunCMake/file/DOWNLOAD-pass-not-set-stderr.txt b/Tests/RunCMake/file-DOWNLOAD/pass-not-set-stderr.txt index 2fa2731..23997c5 100644 --- a/Tests/RunCMake/file/DOWNLOAD-pass-not-set-stderr.txt +++ b/Tests/RunCMake/file-DOWNLOAD/pass-not-set-stderr.txt @@ -1,4 +1,4 @@ -^CMake Error at DOWNLOAD-pass-not-set.cmake:[0-9]+ \(file\): +^CMake Error at pass-not-set.cmake:[0-9]+ \(file\): file DOWNLOAD missing string for USERPWD. Call Stack \(most recent call first\): CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/file/DOWNLOAD-pass-not-set.cmake b/Tests/RunCMake/file-DOWNLOAD/pass-not-set.cmake index 61eff6d..61eff6d 100644 --- a/Tests/RunCMake/file/DOWNLOAD-pass-not-set.cmake +++ b/Tests/RunCMake/file-DOWNLOAD/pass-not-set.cmake diff --git a/Tests/RunCMake/file-DOWNLOAD/range-stdout.txt b/Tests/RunCMake/file-DOWNLOAD/range-stdout.txt new file mode 100644 index 0000000..e2ed7aa --- /dev/null +++ b/Tests/RunCMake/file-DOWNLOAD/range-stdout.txt @@ -0,0 +1,4 @@ +-- status='0;"No error"' +-- status='0;"No error"' +-- status='0;"No error"' +-- status='0;"No error"' diff --git a/Tests/RunCMake/file-DOWNLOAD/range.cmake b/Tests/RunCMake/file-DOWNLOAD/range.cmake new file mode 100644 index 0000000..f77bb28 --- /dev/null +++ b/Tests/RunCMake/file-DOWNLOAD/range.cmake @@ -0,0 +1,15 @@ +include(common.cmake) + +set(file ${CMAKE_CURRENT_BINARY_DIR}/output1.png) +file_download(RANGE_START 0 EXPECTED_MD5 dbd330d52f4dbd60115d4191904ded92) + +set(file ${CMAKE_CURRENT_BINARY_DIR}/output2.png) +file_download(RANGE_END 50 EXPECTED_MD5 8592e5665b839b5d23825dc84c135b61) + +set(file ${CMAKE_CURRENT_BINARY_DIR}/output3.png) +file_download(RANGE_START 10 RANGE_END 50 EXPECTED_MD5 36cd52681e6c6c8fef85fcd9e86fc30d) + +set(file ${CMAKE_CURRENT_BINARY_DIR}/output4.png) +file_download(RANGE_START 0 RANGE_END 50 + RANGE_START 60 RANGE_END 100 + EXPECTED_MD5 c5c9e74e82d493dd901eecccd659cebc) diff --git a/Tests/RunCMake/file/DOWNLOAD-httpheader-not-set-result.txt b/Tests/RunCMake/file-DOWNLOAD/tls-cainfo-not-set-result.txt index d00491f..d00491f 100644 --- a/Tests/RunCMake/file/DOWNLOAD-httpheader-not-set-result.txt +++ b/Tests/RunCMake/file-DOWNLOAD/tls-cainfo-not-set-result.txt diff --git a/Tests/RunCMake/file/DOWNLOAD-tls-cainfo-not-set-stderr.txt b/Tests/RunCMake/file-DOWNLOAD/tls-cainfo-not-set-stderr.txt index 1552baa..d9fa7b7 100644 --- a/Tests/RunCMake/file/DOWNLOAD-tls-cainfo-not-set-stderr.txt +++ b/Tests/RunCMake/file-DOWNLOAD/tls-cainfo-not-set-stderr.txt @@ -1,4 +1,4 @@ -^CMake Error at DOWNLOAD-tls-cainfo-not-set.cmake:[0-9]+ \(file\): +^CMake Error at tls-cainfo-not-set.cmake:[0-9]+ \(file\): file DOWNLOAD missing file value for TLS_CAINFO. Call Stack \(most recent call first\): CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/file/DOWNLOAD-tls-cainfo-not-set.cmake b/Tests/RunCMake/file-DOWNLOAD/tls-cainfo-not-set.cmake index b476425..b476425 100644 --- a/Tests/RunCMake/file/DOWNLOAD-tls-cainfo-not-set.cmake +++ b/Tests/RunCMake/file-DOWNLOAD/tls-cainfo-not-set.cmake diff --git a/Tests/RunCMake/file/DOWNLOAD-hash-mismatch-result.txt b/Tests/RunCMake/file-DOWNLOAD/tls-verify-not-set-result.txt index d00491f..d00491f 100644 --- a/Tests/RunCMake/file/DOWNLOAD-hash-mismatch-result.txt +++ b/Tests/RunCMake/file-DOWNLOAD/tls-verify-not-set-result.txt diff --git a/Tests/RunCMake/file/DOWNLOAD-tls-verify-not-set-stderr.txt b/Tests/RunCMake/file-DOWNLOAD/tls-verify-not-set-stderr.txt index 2f46c0c..c048ea9 100644 --- a/Tests/RunCMake/file/DOWNLOAD-tls-verify-not-set-stderr.txt +++ b/Tests/RunCMake/file-DOWNLOAD/tls-verify-not-set-stderr.txt @@ -1,4 +1,4 @@ -^CMake Error at DOWNLOAD-tls-verify-not-set.cmake:[0-9]+ \(file\): +^CMake Error at tls-verify-not-set.cmake:[0-9]+ \(file\): file DOWNLOAD missing bool value for TLS_VERIFY. Call Stack \(most recent call first\): CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/file/DOWNLOAD-tls-verify-not-set.cmake b/Tests/RunCMake/file-DOWNLOAD/tls-verify-not-set.cmake index 919368c..919368c 100644 --- a/Tests/RunCMake/file/DOWNLOAD-tls-verify-not-set.cmake +++ b/Tests/RunCMake/file-DOWNLOAD/tls-verify-not-set.cmake diff --git a/Tests/RunCMake/file/DOWNLOAD-netrc-bad.txt b/Tests/RunCMake/file-DOWNLOAD/unused-argument-result.txt index e69de29..e69de29 100644 --- a/Tests/RunCMake/file/DOWNLOAD-netrc-bad.txt +++ b/Tests/RunCMake/file-DOWNLOAD/unused-argument-result.txt diff --git a/Tests/RunCMake/file/DOWNLOAD-unused-argument-stderr.txt b/Tests/RunCMake/file-DOWNLOAD/unused-argument-stderr.txt index 82a78c9..f7cfc4f 100644 --- a/Tests/RunCMake/file/DOWNLOAD-unused-argument-stderr.txt +++ b/Tests/RunCMake/file-DOWNLOAD/unused-argument-stderr.txt @@ -1,5 +1,6 @@ -^CMake Warning \(dev\) at DOWNLOAD-unused-argument.cmake:[0-9]+ \(file\): +^CMake Warning \(dev\) at common.cmake:[0-9]+ \(file\): Unexpected argument: JUNK Call Stack \(most recent call first\): + unused-argument.cmake:[0-9]+ \(file_download\) CMakeLists.txt:[0-9]+ \(include\) This warning is for project developers. Use -Wno-dev to suppress it.$ diff --git a/Tests/RunCMake/file-DOWNLOAD/unused-argument.cmake b/Tests/RunCMake/file-DOWNLOAD/unused-argument.cmake new file mode 100644 index 0000000..6f7f597 --- /dev/null +++ b/Tests/RunCMake/file-DOWNLOAD/unused-argument.cmake @@ -0,0 +1,3 @@ +include(common.cmake) + +file_download(JUNK) diff --git a/Tests/RunCMake/file/COPY_FILE-file-INPUT_MAY_BE_RECENT.cmake b/Tests/RunCMake/file/COPY_FILE-file-INPUT_MAY_BE_RECENT.cmake new file mode 100644 index 0000000..88bf448 --- /dev/null +++ b/Tests/RunCMake/file/COPY_FILE-file-INPUT_MAY_BE_RECENT.cmake @@ -0,0 +1,10 @@ +set(oldname "${CMAKE_CURRENT_BINARY_DIR}/input") +set(newname "${CMAKE_CURRENT_BINARY_DIR}/output") +file(WRITE "${oldname}" "") +file(COPY_FILE "${oldname}" "${newname}" INPUT_MAY_BE_RECENT) +if(NOT EXISTS "${oldname}") + message(FATAL_ERROR "The old name does not exist:\n ${oldname}") +endif() +if(NOT EXISTS "${newname}") + message(FATAL_ERROR "The new name does not exist:\n ${newname}") +endif() diff --git a/Tests/RunCMake/file/DOWNLOAD-hash-mismatch-stderr.txt b/Tests/RunCMake/file/DOWNLOAD-hash-mismatch-stderr.txt deleted file mode 100644 index 7a356c1..0000000 --- a/Tests/RunCMake/file/DOWNLOAD-hash-mismatch-stderr.txt +++ /dev/null @@ -1,11 +0,0 @@ -^CMake Error at DOWNLOAD-hash-mismatch.cmake:[0-9]+ \(file\): - file DOWNLOAD HASH mismatch - - for file: \[.*/Tests/RunCMake/file/DOWNLOAD-hash-mismatch-build/hash-mismatch.txt\] - expected hash: \[0123456789abcdef0123456789abcdef01234567\] - actual hash: \[da39a3ee5e6b4b0d3255bfef95601890afd80709\] - -Call Stack \(most recent call first\): - CMakeLists.txt:[0-9]+ \(include\) -+ -status='1;HASH mismatch: expected: 0123456789abcdef0123456789abcdef01234567 actual: da39a3ee5e6b4b0d3255bfef95601890afd80709'$ diff --git a/Tests/RunCMake/file/DOWNLOAD-hash-mismatch.cmake b/Tests/RunCMake/file/DOWNLOAD-hash-mismatch.cmake deleted file mode 100644 index a91b217..0000000 --- a/Tests/RunCMake/file/DOWNLOAD-hash-mismatch.cmake +++ /dev/null @@ -1,10 +0,0 @@ -if(NOT "${CMAKE_CURRENT_SOURCE_DIR}" MATCHES "^/") - set(slash /) -endif() -file(DOWNLOAD - "file://${slash}${CMAKE_CURRENT_SOURCE_DIR}/DOWNLOAD-hash-mismatch.txt" - ${CMAKE_CURRENT_BINARY_DIR}/hash-mismatch.txt - EXPECTED_HASH SHA1=0123456789abcdef0123456789abcdef01234567 - STATUS status - ) -message("status='${status}'") diff --git a/Tests/RunCMake/file/DOWNLOAD-hash-mismatch.txt b/Tests/RunCMake/file/DOWNLOAD-hash-mismatch.txt deleted file mode 100644 index e69de29..0000000 --- a/Tests/RunCMake/file/DOWNLOAD-hash-mismatch.txt +++ /dev/null diff --git a/Tests/RunCMake/file/DOWNLOAD-no-save-hash.cmake b/Tests/RunCMake/file/DOWNLOAD-no-save-hash.cmake deleted file mode 100644 index ce959a7..0000000 --- a/Tests/RunCMake/file/DOWNLOAD-no-save-hash.cmake +++ /dev/null @@ -1,8 +0,0 @@ -if(NOT "${CMAKE_CURRENT_SOURCE_DIR}" MATCHES "^/") - set(slash /) -endif() -file(DOWNLOAD - "file://${slash}${CMAKE_CURRENT_SOURCE_DIR}/DOWNLOAD-no-save-md5.txt" - EXPECTED_HASH MD5=55555555555555555555555555555555 - STATUS status - ) diff --git a/Tests/RunCMake/file/DOWNLOAD-unused-argument.cmake b/Tests/RunCMake/file/DOWNLOAD-unused-argument.cmake deleted file mode 100644 index 2fa5482..0000000 --- a/Tests/RunCMake/file/DOWNLOAD-unused-argument.cmake +++ /dev/null @@ -1,8 +0,0 @@ -if(NOT "${CMAKE_CURRENT_SOURCE_DIR}" MATCHES "^/") - set(slash /) -endif() -file(DOWNLOAD - "file://${slash}${CMAKE_CURRENT_SOURCE_DIR}/DOWNLOAD-unused-argument.txt" - "${CMAKE_CURRENT_BINARY_DIR}/unused-argument.txt" - JUNK - ) diff --git a/Tests/RunCMake/file/RunCMakeTest.cmake b/Tests/RunCMake/file/RunCMakeTest.cmake index 4ad00ff..752f7a0 100644 --- a/Tests/RunCMake/file/RunCMakeTest.cmake +++ b/Tests/RunCMake/file/RunCMakeTest.cmake @@ -4,14 +4,6 @@ run_cmake(CREATE_LINK) run_cmake(CREATE_LINK-COPY_ON_ERROR) run_cmake(CREATE_LINK-noarg) run_cmake(CREATE_LINK-noexist) -run_cmake(DOWNLOAD-hash-mismatch) -run_cmake(DOWNLOAD-unused-argument) -run_cmake(DOWNLOAD-httpheader-not-set) -run_cmake(DOWNLOAD-netrc-bad) -run_cmake(DOWNLOAD-tls-cainfo-not-set) -run_cmake(DOWNLOAD-tls-verify-not-set) -run_cmake(DOWNLOAD-pass-not-set) -run_cmake(DOWNLOAD-no-save-hash) run_cmake(TOUCH) run_cmake(TOUCH-error-in-source-directory) run_cmake(TOUCH-error-missing-directory) @@ -59,6 +51,7 @@ run_cmake_script(COPY_FILE-dirlink-to-file-fail) run_cmake_script(COPY_FILE-file-to-file) run_cmake_script(COPY_FILE-file-to-dir-capture) run_cmake_script(COPY_FILE-file-to-dir-fail) +run_cmake_script(COPY_FILE-file-INPUT_MAY_BE_RECENT) run_cmake_script(COPY_FILE-file-ONLY_IF_DIFFERENT-capture) run_cmake_script(COPY_FILE-file-ONLY_IF_DIFFERENT-fail) run_cmake_script(COPY_FILE-file-ONLY_IF_DIFFERENT-no-overwrite) diff --git a/Utilities/ClangTidyModule/CMakeLists.txt b/Utilities/ClangTidyModule/CMakeLists.txt index c51f43a..6fc54b1 100644 --- a/Utilities/ClangTidyModule/CMakeLists.txt +++ b/Utilities/ClangTidyModule/CMakeLists.txt @@ -22,6 +22,8 @@ add_library(cmake-clang-tidy-module MODULE UseCmstrlenCheck.h UseCmsysFstreamCheck.cxx UseCmsysFstreamCheck.h + UsePragmaOnceCheck.cxx + UsePragmaOnceCheck.h ) target_include_directories(cmake-clang-tidy-module PRIVATE ${CLANG_INCLUDE_DIRS}) target_link_libraries(cmake-clang-tidy-module PRIVATE clang-tidy) diff --git a/Utilities/ClangTidyModule/Module.cxx b/Utilities/ClangTidyModule/Module.cxx index 7ef8e7d..c747cee 100644 --- a/Utilities/ClangTidyModule/Module.cxx +++ b/Utilities/ClangTidyModule/Module.cxx @@ -7,6 +7,7 @@ #include "UseBespokeEnumClassCheck.h" #include "UseCmstrlenCheck.h" #include "UseCmsysFstreamCheck.h" +#include "UsePragmaOnceCheck.h" namespace clang { namespace tidy { @@ -23,6 +24,7 @@ public: "cmake-use-bespoke-enum-class"); CheckFactories.registerCheck<OstringstreamUseCmstrcatCheck>( "cmake-ostringstream-use-cmstrcat"); + CheckFactories.registerCheck<UsePragmaOnceCheck>("cmake-use-pragma-once"); } }; diff --git a/Utilities/ClangTidyModule/Tests/CMakeLists.txt b/Utilities/ClangTidyModule/Tests/CMakeLists.txt index 5bf0e89..b53d5d2 100644 --- a/Utilities/ClangTidyModule/Tests/CMakeLists.txt +++ b/Utilities/ClangTidyModule/Tests/CMakeLists.txt @@ -14,3 +14,4 @@ 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) +add_run_clang_tidy_test(cmake-use-pragma-once) diff --git a/Utilities/ClangTidyModule/Tests/RunClangTidy.cmake b/Utilities/ClangTidyModule/Tests/RunClangTidy.cmake index 7fd7cdd..98770d7 100644 --- a/Utilities/ClangTidyModule/Tests/RunClangTidy.cmake +++ b/Utilities/ClangTidyModule/Tests/RunClangTidy.cmake @@ -13,12 +13,22 @@ endif() set(source_file "${RunClangTidy_BINARY_DIR}/${CHECK_NAME}.cxx") configure_file("${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}.cxx" "${source_file}" COPYONLY) +file(GLOB header_files RELATIVE "${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}" "${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}/*") +file(REMOVE_RECURSE "${RunClangTiy_BINARY_DIR}/${CHECK_NAME}") +foreach(header_file IN LISTS header_files) + if(NOT header_file MATCHES "-fixit\\.h\$") + file(MAKE_DIRECTORY "${RunClangTidy_BINARY_DIR}/${CHECK_NAME}") + configure_file("${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}/${header_file}" "${RunClangTidy_BINARY_DIR}/${CHECK_NAME}/${header_file}" COPYONLY) + endif() +endforeach() + set(command "${CLANG_TIDY_COMMAND}" "--load=${CLANG_TIDY_MODULE}" "--checks=-*,${CHECK_NAME}" "--fix" "--format-style=file" + "--header-filter=/${CHECK_NAME}/" ${config_arg} "${source_file}" -- @@ -44,18 +54,38 @@ if(NOT actual_stdout STREQUAL expect_stdout) string(APPEND RunClangTidy_TEST_FAILED "Expected stdout:\n${expect_stdout_formatted}\nActual stdout:\n${actual_stdout_formatted}\n") endif() -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() +function(check_fixit expected fallback_expected actual) + if(EXISTS "${expected}") + set(expect_fixit_file "${expected}") + else() + set(expect_fixit_file "${fallback_expected}") + endif() + file(READ "${expect_fixit_file}" expect_fixit) + file(READ "${actual}" 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 for ${actual}:\n${expect_fixit_formatted}\nActual fixit:\n${actual_fixit_formatted}\n") + set(RunClangTidy_TEST_FAILED "${RunClangTidy_TEST_FAILED}" PARENT_SCOPE) + endif() +endfunction() + +check_fixit( + "${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}-fixit.cxx" + "${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}.cxx" + "${source_file}" + ) + +foreach(header_file IN LISTS header_files) + if(NOT header_file MATCHES "-fixit\\.h\$") + string(REGEX REPLACE "\\.h\$" "-fixit.h" header_fixit "${header_file}") + check_fixit( + "${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}/${header_fixit}" + "${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}/${header_file}" + "${RunClangTidy_BINARY_DIR}/${CHECK_NAME}/${header_file}" + ) + endif() +endforeach() if(RunClangTidy_TEST_FAILED) string(REPLACE ";" " " command_formatted "${command}") diff --git a/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once-stdout.txt b/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once-stdout.txt new file mode 100644 index 0000000..e80e4a4 --- /dev/null +++ b/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once-stdout.txt @@ -0,0 +1,25 @@ +cmake-use-pragma-once/cmake-use-pragma-once-both.h:1:1: warning: use #pragma once [cmake-use-pragma-once] +#ifndef BOTH_H +^~~~~~~~~~~~~~ +cmake-use-pragma-once/cmake-use-pragma-once-both.h:1:1: note: FIX-IT applied suggested code changes +cmake-use-pragma-once/cmake-use-pragma-once-both.h:2:1: note: FIX-IT applied suggested code changes +#define BOTH_H +^ +cmake-use-pragma-once/cmake-use-pragma-once-both.h:10:1: note: FIX-IT applied suggested code changes +#endif +^ +cmake-use-pragma-once/cmake-use-pragma-once-include-guards.h:1:1: warning: use #pragma once [cmake-use-pragma-once] +#ifndef INCLUDE_GUARDS_H +^~~~~~~~~~~~~~~~~~~~~~~~ +#pragma once +cmake-use-pragma-once/cmake-use-pragma-once-include-guards.h:1:1: note: FIX-IT applied suggested code changes +cmake-use-pragma-once/cmake-use-pragma-once-include-guards.h:2:1: note: FIX-IT applied suggested code changes +#define INCLUDE_GUARDS_H +^ +cmake-use-pragma-once/cmake-use-pragma-once-include-guards.h:9:1: note: FIX-IT applied suggested code changes +#endif +^ +cmake-use-pragma-once/cmake-use-pragma-once-neither.h:1:1: warning: use #pragma once [cmake-use-pragma-once] +int neither() +^ +cmake-use-pragma-once/cmake-use-pragma-once-neither.h:1:1: note: FIX-IT applied suggested code changes diff --git a/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once.cxx b/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once.cxx new file mode 100644 index 0000000..a571bc1 --- /dev/null +++ b/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once.cxx @@ -0,0 +1,5 @@ +#include "cmake-use-pragma-once/cmake-use-pragma-once.h" + +#include "cmake-use-pragma-once/cmake-use-pragma-once-both.h" +#include "cmake-use-pragma-once/cmake-use-pragma-once-include-guards.h" +#include "cmake-use-pragma-once/cmake-use-pragma-once-neither.h" diff --git a/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once-both-fixit.h b/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once-both-fixit.h new file mode 100644 index 0000000..73c9720 --- /dev/null +++ b/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once-both-fixit.h @@ -0,0 +1,8 @@ + + +#pragma once + +int both() +{ + return 0; +} diff --git a/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once-both.h b/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once-both.h new file mode 100644 index 0000000..fdf3cd3 --- /dev/null +++ b/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once-both.h @@ -0,0 +1,10 @@ +#ifndef BOTH_H +#define BOTH_H +#pragma once + +int both() +{ + return 0; +} + +#endif diff --git a/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once-include-guards-fixit.h b/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once-include-guards-fixit.h new file mode 100644 index 0000000..36461c2 --- /dev/null +++ b/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once-include-guards-fixit.h @@ -0,0 +1,6 @@ +#pragma once + +int includeGuards() +{ + return 0; +} diff --git a/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once-include-guards.h b/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once-include-guards.h new file mode 100644 index 0000000..687306d --- /dev/null +++ b/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once-include-guards.h @@ -0,0 +1,9 @@ +#ifndef INCLUDE_GUARDS_H +#define INCLUDE_GUARDS_H + +int includeGuards() +{ + return 0; +} + +#endif diff --git a/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once-neither-fixit.h b/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once-neither-fixit.h new file mode 100644 index 0000000..eb5c6dd --- /dev/null +++ b/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once-neither-fixit.h @@ -0,0 +1,5 @@ +#pragma once +int neither() +{ + return 0; +} diff --git a/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once-neither.h b/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once-neither.h new file mode 100644 index 0000000..c779ca0 --- /dev/null +++ b/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once-neither.h @@ -0,0 +1,4 @@ +int neither() +{ + return 0; +} diff --git a/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once.h b/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once.h new file mode 100644 index 0000000..b0b2ea2 --- /dev/null +++ b/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once.h @@ -0,0 +1,6 @@ +#pragma once + +int once() +{ + return 0; +} diff --git a/Utilities/ClangTidyModule/UsePragmaOnceCheck.cxx b/Utilities/ClangTidyModule/UsePragmaOnceCheck.cxx new file mode 100644 index 0000000..7a42798 --- /dev/null +++ b/Utilities/ClangTidyModule/UsePragmaOnceCheck.cxx @@ -0,0 +1,325 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ + +/* This code was originally taken from part of the Clang-Tidy LLVM project and + * modified for use with CMake under the following original license: */ + +//===--- HeaderGuard.cpp - clang-tidy +//-------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM +// Exceptions. See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "UsePragmaOnceCheck.h" + +#include <algorithm> +#include <cassert> + +#include <clang/Frontend/CompilerInstance.h> +#include <clang/Lex/PPCallbacks.h> +#include <clang/Lex/Preprocessor.h> +#include <clang/Tooling/Tooling.h> +#include <llvm/Support/Path.h> + +namespace clang { +namespace tidy { +namespace cmake { + +/// canonicalize a path by removing ./ and ../ components. +static std::string cleanPath(StringRef Path) +{ + SmallString<256> Result = Path; + llvm::sys::path::remove_dots(Result, true); + return std::string(Result.str()); +} + +namespace { +// This class is a workaround for the fact that PPCallbacks doesn't give us the +// location of the hash for an #ifndef, #define, or #endif, so we have to find +// it ourselves. We can't lex backwards, and attempting to turn on the +// preprocessor's backtracking functionality wreaks havoc, so we have to +// instantiate a second lexer and lex all the way from the beginning of the +// file. Cache the results of this lexing so that we don't have to do it more +// times than needed. +// +// TODO: Upstream a change to LLVM to give us the location of the hash in +// PPCallbacks so we don't have to do this workaround. +class DirectiveCache +{ +public: + DirectiveCache(Preprocessor* PP, FileID FID) + : PP(PP) + , FID(FID) + { + SourceManager& SM = this->PP->getSourceManager(); + const FileEntry* Entry = SM.getFileEntryForID(FID); + assert(Entry && "Invalid FileID given"); + + Lexer MyLexer(FID, SM.getMemoryBufferForFileOrFake(Entry), SM, + this->PP->getLangOpts()); + Token Tok; + + while (!MyLexer.LexFromRawLexer(Tok)) { + if (Tok.getKind() == tok::hash) { + assert(SM.getFileID(Tok.getLocation()) == this->FID && + "Token FileID does not match passed FileID"); + if (!this->HashLocs.empty()) { + assert(SM.getFileOffset(this->HashLocs.back()) < + SM.getFileOffset(Tok.getLocation()) && + "Tokens in file are not in order"); + } + + this->HashLocs.push_back(Tok.getLocation()); + } + } + } + + SourceRange createRangeForIfndef(SourceLocation IfndefMacroTokLoc) + { + // The #ifndef of an include guard is likely near the beginning of the + // file, so search from the front. + return SourceRange(this->findPreviousHashFromFront(IfndefMacroTokLoc), + IfndefMacroTokLoc); + } + + SourceRange createRangeForDefine(SourceLocation DefineMacroTokLoc) + { + // The #define of an include guard is likely near the beginning of the + // file, so search from the front. + return SourceRange(this->findPreviousHashFromFront(DefineMacroTokLoc), + DefineMacroTokLoc); + } + + SourceRange createRangeForEndif(SourceLocation EndifLoc) + { + // The #endif of an include guard is likely near the end of the file, so + // search from the back. + return SourceRange(this->findPreviousHashFromBack(EndifLoc), EndifLoc); + } + +private: + Preprocessor* PP; + FileID FID; + SmallVector<SourceLocation> HashLocs; + + SourceLocation findPreviousHashFromFront(SourceLocation Loc) + { + SourceManager& SM = this->PP->getSourceManager(); + Loc = SM.getExpansionLoc(Loc); + assert(SM.getFileID(Loc) == this->FID && + "Loc FileID does not match our FileID"); + + auto It = std::find_if( + this->HashLocs.begin(), this->HashLocs.end(), + [&SM, &Loc](const SourceLocation& OtherLoc) -> bool { + return SM.getFileOffset(OtherLoc) >= SM.getFileOffset(Loc); + }); + assert(It != this->HashLocs.begin() && + "No hash associated with passed Loc"); + return *--It; + } + + SourceLocation findPreviousHashFromBack(SourceLocation Loc) + { + SourceManager& SM = this->PP->getSourceManager(); + Loc = SM.getExpansionLoc(Loc); + assert(SM.getFileID(Loc) == this->FID && + "Loc FileID does not match our FileID"); + + auto It = + std::find_if(this->HashLocs.rbegin(), this->HashLocs.rend(), + [&SM, &Loc](const SourceLocation& OtherLoc) -> bool { + return SM.getFileOffset(OtherLoc) < SM.getFileOffset(Loc); + }); + assert(It != this->HashLocs.rend() && + "No hash associated with passed Loc"); + return *It; + } +}; + +class UsePragmaOncePPCallbacks : public PPCallbacks +{ +public: + UsePragmaOncePPCallbacks(Preprocessor* PP, UsePragmaOnceCheck* Check) + : PP(PP) + , Check(Check) + { + } + + void FileChanged(SourceLocation Loc, FileChangeReason Reason, + SrcMgr::CharacteristicKind FileType, + FileID PrevFID) override + { + // Record all files we enter. We'll need them to diagnose headers without + // guards. + SourceManager& SM = this->PP->getSourceManager(); + if (Reason == EnterFile && FileType == SrcMgr::C_User) { + if (const FileEntry* FE = SM.getFileEntryForID(SM.getFileID(Loc))) { + std::string FileName = cleanPath(FE->getName()); + this->Files[FileName] = FE; + } + } + } + + void Ifndef(SourceLocation Loc, const Token& MacroNameTok, + const MacroDefinition& MD) override + { + if (MD) { + return; + } + + // Record #ifndefs that succeeded. We also need the Location of the Name. + this->Ifndefs[MacroNameTok.getIdentifierInfo()] = + std::make_pair(Loc, MacroNameTok.getLocation()); + } + + void MacroDefined(const Token& MacroNameTok, + const MacroDirective* MD) override + { + // Record all defined macros. We store the whole token to get info on the + // name later. + this->Macros.emplace_back(MacroNameTok, MD->getMacroInfo()); + } + + void Endif(SourceLocation Loc, SourceLocation IfLoc) override + { + // Record all #endif and the corresponding #ifs (including #ifndefs). + this->EndIfs[IfLoc] = Loc; + } + + void EndOfMainFile() override + { + // Now that we have all this information from the preprocessor, use it! + SourceManager& SM = this->PP->getSourceManager(); + + for (const auto& MacroEntry : this->Macros) { + const MacroInfo* MI = MacroEntry.second; + + // We use clang's header guard detection. This has the advantage of also + // emitting a warning for cases where a pseudo header guard is found but + // preceded by something blocking the header guard optimization. + if (!MI->isUsedForHeaderGuard()) { + continue; + } + + const FileEntry* FE = + SM.getFileEntryForID(SM.getFileID(MI->getDefinitionLoc())); + std::string FileName = cleanPath(FE->getName()); + this->Files.erase(FileName); + + // Look up Locations for this guard. + SourceLocation Ifndef = + this->Ifndefs[MacroEntry.first.getIdentifierInfo()].second; + SourceLocation Define = MacroEntry.first.getLocation(); + SourceLocation EndIf = + this + ->EndIfs[this->Ifndefs[MacroEntry.first.getIdentifierInfo()].first]; + + StringRef CurHeaderGuard = + MacroEntry.first.getIdentifierInfo()->getName(); + std::vector<FixItHint> FixIts; + + HeaderSearch& HeaderInfo = this->PP->getHeaderSearchInfo(); + + HeaderFileInfo& Info = HeaderInfo.getFileInfo(FE); + + DirectiveCache Cache(this->PP, SM.getFileID(MI->getDefinitionLoc())); + SourceRange IfndefSrcRange = Cache.createRangeForIfndef(Ifndef); + SourceRange DefineSrcRange = Cache.createRangeForDefine(Define); + SourceRange EndifSrcRange = Cache.createRangeForEndif(EndIf); + + if (Info.isPragmaOnce) { + FixIts.push_back(FixItHint::CreateRemoval(IfndefSrcRange)); + } else { + FixIts.push_back( + FixItHint::CreateReplacement(IfndefSrcRange, "#pragma once")); + } + + FixIts.push_back(FixItHint::CreateRemoval(DefineSrcRange)); + FixIts.push_back(FixItHint::CreateRemoval(EndifSrcRange)); + + this->Check->diag(IfndefSrcRange.getBegin(), "use #pragma once") + << FixIts; + } + + // Emit warnings for headers that are missing guards. + checkGuardlessHeaders(); + clearAllState(); + } + + /// Looks for files that were visited but didn't have a header guard. + /// Emits a warning with fixits suggesting adding one. + void checkGuardlessHeaders() + { + // Look for header files that didn't have a header guard. Emit a warning + // and fix-its to add the guard. + // TODO: Insert the guard after top comments. + for (const auto& FE : this->Files) { + StringRef FileName = FE.getKey(); + if (!Check->shouldSuggestToAddPragmaOnce(FileName)) { + continue; + } + + SourceManager& SM = this->PP->getSourceManager(); + FileID FID = SM.translateFile(FE.getValue()); + SourceLocation StartLoc = SM.getLocForStartOfFile(FID); + if (StartLoc.isInvalid()) { + continue; + } + + HeaderSearch& HeaderInfo = this->PP->getHeaderSearchInfo(); + + HeaderFileInfo& Info = HeaderInfo.getFileInfo(FE.second); + if (Info.isPragmaOnce) { + continue; + } + + this->Check->diag(StartLoc, "use #pragma once") + << FixItHint::CreateInsertion(StartLoc, "#pragma once\n"); + } + } + +private: + void clearAllState() + { + this->Macros.clear(); + this->Files.clear(); + this->Ifndefs.clear(); + this->EndIfs.clear(); + } + + std::vector<std::pair<Token, const MacroInfo*>> Macros; + llvm::StringMap<const FileEntry*> Files; + std::map<const IdentifierInfo*, std::pair<SourceLocation, SourceLocation>> + Ifndefs; + std::map<SourceLocation, SourceLocation> EndIfs; + + Preprocessor* PP; + UsePragmaOnceCheck* Check; +}; +} // namespace + +void UsePragmaOnceCheck::storeOptions(ClangTidyOptions::OptionMap& Opts) +{ + this->Options.store(Opts, "HeaderFileExtensions", + RawStringHeaderFileExtensions); +} + +void UsePragmaOnceCheck::registerPPCallbacks(const SourceManager& SM, + Preprocessor* PP, + Preprocessor* ModuleExpanderPP) +{ + PP->addPPCallbacks(std::make_unique<UsePragmaOncePPCallbacks>(PP, this)); +} + +bool UsePragmaOnceCheck::shouldSuggestToAddPragmaOnce(StringRef FileName) +{ + return utils::isFileExtension(FileName, this->HeaderFileExtensions); +} + +} // namespace cmake +} // namespace tidy +} // namespace clang diff --git a/Utilities/ClangTidyModule/UsePragmaOnceCheck.h b/Utilities/ClangTidyModule/UsePragmaOnceCheck.h new file mode 100644 index 0000000..08c2099 --- /dev/null +++ b/Utilities/ClangTidyModule/UsePragmaOnceCheck.h @@ -0,0 +1,60 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ + +/* This code was originally taken from part of the Clang-Tidy LLVM project and + * modified for use with CMake under the following original license: */ + +//===--- HeaderGuard.h - clang-tidy -----------------------------*- C++ +//-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM +// Exceptions. See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include <clang-tidy/ClangTidyCheck.h> +#include <clang-tidy/utils/FileExtensionsUtils.h> + +namespace clang { +namespace tidy { +namespace cmake { + +/// Finds and replaces header guards with pragma once. +/// The check supports these options: +/// - `HeaderFileExtensions`: a semicolon-separated list of filename +/// extensions of header files (The filename extension should not contain +/// "." prefix). ";h;hh;hpp;hxx" by default. +/// +/// For extension-less header files, using an empty string or leaving an +/// empty string between ";" if there are other filename extensions. +class UsePragmaOnceCheck : public ClangTidyCheck +{ +public: + UsePragmaOnceCheck(StringRef Name, ClangTidyContext* Context) + : ClangTidyCheck(Name, Context) + , RawStringHeaderFileExtensions(Options.getLocalOrGlobal( + "HeaderFileExtensions", utils::defaultHeaderFileExtensions())) + { + utils::parseFileExtensions(RawStringHeaderFileExtensions, + HeaderFileExtensions, + utils::defaultFileExtensionDelimiters()); + } + void storeOptions(ClangTidyOptions::OptionMap& Opts) override; + void registerPPCallbacks(const SourceManager& SM, Preprocessor* PP, + Preprocessor* ModuleExpanderPP) override; + + /// Returns ``true`` if the check should add pragma once to the file + /// if it has none. + virtual bool shouldSuggestToAddPragmaOnce(StringRef Filename); + +private: + std::string RawStringHeaderFileExtensions; + utils::FileExtensionsSet HeaderFileExtensions; +}; + +} // namespace cmake +} // namespace tidy +} // namespace clang |