summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitlab-ci.yml70
-rw-r--r--.gitlab/artifacts.yml3
-rw-r--r--.gitlab/ci/cmake_version.cmake3
-rwxr-xr-x.gitlab/ci/cmake_version.sh2
-rw-r--r--.gitlab/ci/configure_fedora31_ninja.cmake4
-rw-r--r--.gitlab/ci/ctest_test.cmake5
-rw-r--r--.gitlab/ci/gitlab_ci.cmake6
-rw-r--r--.gitlab/os-linux.yml29
-rw-r--r--.gitlab/os-macos.yml4
-rw-r--r--.gitlab/os-windows.yml2
-rw-r--r--.gitlab/rules.yml15
-rw-r--r--Help/command/cmake_language.rst123
-rw-r--r--Help/command/return.rst1
-rw-r--r--Help/guide/importing-exporting/index.rst7
-rw-r--r--Help/guide/tutorial/index.rst3
-rw-r--r--Help/guide/user-interaction/VS-Choose-Arch.png (renamed from Help/manual/VS-Choose-Arch.png)bin11130 -> 11130 bytes
-rw-r--r--Help/guide/user-interaction/index.rst10
-rw-r--r--Help/guide/using-dependencies/index.rst4
-rw-r--r--Help/manual/cmake-modules.7.rst1
-rw-r--r--Help/manual/cmake.1.rst7
-rw-r--r--Help/module/CheckCompilerFlag.rst1
-rw-r--r--Help/release/dev/FindPython-version_range.rst5
-rw-r--r--Help/release/dev/check-source-modules.rst4
-rw-r--r--Help/release/dev/cmake-gui-environment.rst4
-rw-r--r--Help/release/dev/cmake_language-DEFER.rst5
-rw-r--r--Help/variable/CMAKE_CURRENT_LIST_LINE.rst4
-rw-r--r--Help/variable/CMAKE_LANG_COMPILER_ID.rst1
-rw-r--r--Modules/CMakeCompilerIdDetection.cmake1
-rw-r--r--Modules/CMakeGenericSystem.cmake4
-rw-r--r--Modules/CMakeOBJCInformation.cmake2
-rw-r--r--Modules/CMakeOBJCXXInformation.cmake2
-rw-r--r--Modules/CheckCCompilerFlag.cmake26
-rw-r--r--Modules/CheckCXXCompilerFlag.cmake26
-rw-r--r--Modules/CheckCompilerFlag.cmake105
-rw-r--r--Modules/CheckFortranCompilerFlag.cmake28
-rw-r--r--Modules/CheckOBJCCompilerFlag.cmake27
-rw-r--r--Modules/CheckOBJCXXCompilerFlag.cmake27
-rw-r--r--Modules/Compiler/IntelClang-DetermineCompiler.cmake7
-rw-r--r--Modules/FindCUDA/select_compute_arch.cmake16
-rw-r--r--Modules/FindJNI.cmake2
-rw-r--r--Modules/FindPackageHandleStandardArgs.cmake12
-rw-r--r--Modules/FindPkgConfig.cmake12
-rw-r--r--Modules/FindPython.cmake52
-rw-r--r--Modules/FindPython/Support.cmake409
-rw-r--r--Modules/FindPython2.cmake4
-rw-r--r--Modules/FindPython3.cmake4
-rw-r--r--Source/CMakeLists.txt1
-rw-r--r--Source/CMakeVersion.cmake2
-rw-r--r--Source/CTest/cmCTestBuildHandler.cxx32
-rw-r--r--Source/CTest/cmCTestGenericHandler.cxx3
-rw-r--r--Source/CTest/cmCTestGenericHandler.h1
-rw-r--r--Source/CTest/cmCTestLaunch.cxx361
-rw-r--r--Source/CTest/cmCTestLaunch.h55
-rw-r--r--Source/CTest/cmCTestLaunchReporter.cxx316
-rw-r--r--Source/CTest/cmCTestLaunchReporter.h81
-rw-r--r--Source/QtDialog/AddCacheEntry.cxx6
-rw-r--r--Source/QtDialog/CMakeLists.txt4
-rw-r--r--Source/QtDialog/CMakeSetupDialog.cxx269
-rw-r--r--Source/QtDialog/CMakeSetupDialog.h1
-rw-r--r--Source/QtDialog/CMakeSetupDialog.ui76
-rw-r--r--Source/QtDialog/EnvironmentDialog.cxx194
-rw-r--r--Source/QtDialog/EnvironmentDialog.h59
-rw-r--r--Source/QtDialog/EnvironmentDialog.ui130
-rw-r--r--Source/QtDialog/FirstConfigure.cxx33
-rw-r--r--Source/QtDialog/FirstConfigure.h2
-rw-r--r--Source/QtDialog/QCMake.cxx87
-rw-r--r--Source/QtDialog/QCMake.h8
-rw-r--r--Source/QtDialog/QCMakeCacheView.cxx8
-rw-r--r--Source/QtDialog/QCMakeWidgets.cxx4
-rw-r--r--Source/QtDialog/WarningMessagesDialog.cxx24
-rw-r--r--Source/cmCMakeLanguageCommand.cxx382
-rw-r--r--Source/cmCommandArgumentParserHelper.cxx12
-rw-r--r--Source/cmConditionEvaluator.cxx8
-rw-r--r--Source/cmConditionEvaluator.h4
-rw-r--r--Source/cmExtraSublimeTextGenerator.cxx6
-rw-r--r--Source/cmFindPackageCommand.cxx24
-rw-r--r--Source/cmFunctionCommand.cxx3
-rw-r--r--Source/cmGeneratorTarget.cxx51
-rw-r--r--Source/cmGeneratorTarget.h14
-rw-r--r--Source/cmGlobalGenerator.cxx18
-rw-r--r--Source/cmGlobalGenerator.h5
-rw-r--r--Source/cmGlobalGhsMultiGenerator.cxx36
-rw-r--r--Source/cmGlobalUnixMakefileGenerator3.cxx4
-rw-r--r--Source/cmGlobalVisualStudio7Generator.cxx4
-rw-r--r--Source/cmGlobalXCodeGenerator.cxx5
-rw-r--r--Source/cmIfCommand.cxx24
-rw-r--r--Source/cmListFileCache.cxx7
-rw-r--r--Source/cmListFileCache.h18
-rw-r--r--Source/cmLocalVisualStudio7Generator.cxx12
-rw-r--r--Source/cmMacroCommand.cxx3
-rw-r--r--Source/cmMakefile.cxx254
-rw-r--r--Source/cmMakefile.h50
-rw-r--r--Source/cmState.cxx15
-rw-r--r--Source/cmState.h2
-rw-r--r--Source/cmStateTypes.h1
-rw-r--r--Source/cmSystemTools.cxx3
-rw-r--r--Source/cmTargetLinkLibrariesCommand.cxx3
-rw-r--r--Source/cmTimestamp.cxx3
-rw-r--r--Source/cmVisualStudio10TargetGenerator.cxx29
-rw-r--r--Source/cmWhileCommand.cxx14
-rw-r--r--Source/cmake.cxx7
-rw-r--r--Source/cmake.h2
-rw-r--r--Source/kwsys/RegularExpression.cxx2
-rw-r--r--Templates/MSBuild/FlagTables/v142_CL.json14
-rw-r--r--Tests/CMakeGUI/CMakeGUITest.cmake9
-rw-r--r--Tests/CMakeGUI/CMakeGUITest.cxx104
-rw-r--r--Tests/CMakeGUI/CMakeGUITest.h5
-rw-r--r--Tests/CMakeGUI/CMakeLists.txt29
-rw-r--r--Tests/CMakeGUI/CatchShow.cxx25
-rw-r--r--Tests/CMakeGUI/CatchShow.h41
-rw-r--r--Tests/CMakeGUI/CatchShowTest.cxx49
-rw-r--r--Tests/CMakeGUI/CatchShowTest.h15
-rw-r--r--Tests/CMakeGUI/EnvironmentDialogTest.cxx142
-rw-r--r--Tests/CMakeGUI/EnvironmentDialogTest.h15
-rw-r--r--Tests/CMakeGUI/environment/CMakeLists.txt.in18
-rw-r--r--Tests/CMakeGUI/simpleConfigure-fail/CMakeLists.txt.in5
-rw-r--r--Tests/CMakeGUI/simpleConfigure-success/CMakeLists.txt.in4
-rw-r--r--Tests/FindPython/CMakeLists.txt104
-rw-r--r--Tests/FindPython/VersionRange/CMakeLists.txt55
-rw-r--r--Tests/IncludeDirectories/CMakeLists.txt1
-rw-r--r--Tests/IncludeDirectories/SystemIncludeDirectoriesPerLang/CMakeLists.txt23
-rw-r--r--Tests/IncludeDirectories/SystemIncludeDirectoriesPerLang/cxx_system_include/header.h10
-rw-r--r--Tests/IncludeDirectories/SystemIncludeDirectoriesPerLang/main.c4
-rw-r--r--Tests/IncludeDirectories/SystemIncludeDirectoriesPerLang/smoke_out_includes.cxx7
-rw-r--r--Tests/ObjCXX/CMakeLists.txt1
-rw-r--r--Tests/ObjCXX/cxx-as-objcxx/CMakeLists.txt5
-rw-r--r--Tests/ObjCXX/cxx-as-objcxx/main.cpp6
-rw-r--r--Tests/RunCMake/CMakeLists.txt6
-rwxr-xr-xTests/RunCMake/CommandLine/trace-json-v1-check.py2
-rw-r--r--Tests/RunCMake/FPHSA/RunCMakeTest.cmake2
-rw-r--r--Tests/RunCMake/FPHSA/range_empty-1-stderr.txt6
-rw-r--r--Tests/RunCMake/FPHSA/range_empty-1.cmake1
-rw-r--r--Tests/RunCMake/FPHSA/range_empty-2-stderr.txt6
-rw-r--r--Tests/RunCMake/FPHSA/range_empty-2.cmake1
-rw-r--r--Tests/RunCMake/VS10Project/LanguageStandard-check.cmake23
-rw-r--r--Tests/RunCMake/VS10Project/LanguageStandard.cmake5
-rw-r--r--Tests/RunCMake/VS10Project/NoImpLib-check.cmake23
-rw-r--r--Tests/RunCMake/VS10Project/NoImpLib.cmake3
-rw-r--r--Tests/RunCMake/VS10Project/RunCMakeTest.cmake5
-rw-r--r--Tests/RunCMake/XcodeProject/RunCMakeTest.cmake23
-rw-r--r--Tests/RunCMake/cmake_language/CallInvalidCommand.cmake2
-rw-r--r--Tests/RunCMake/cmake_language/RunCMakeTest.cmake61
-rw-r--r--Tests/RunCMake/cmake_language/call_expand_command_name.cmake2
-rw-r--r--Tests/RunCMake/cmake_language/call_expanded_command.cmake2
-rw-r--r--Tests/RunCMake/cmake_language/call_expanded_command_and_arguments-stderr.txt2
-rw-r--r--Tests/RunCMake/cmake_language/call_invalid_command-result.txt (renamed from Tests/RunCMake/FPHSA/range_empty-2-result.txt)0
-rw-r--r--Tests/RunCMake/cmake_language/call_invalid_command-stderr.txt4
-rw-r--r--Tests/RunCMake/cmake_language/call_invalid_command.cmake15
-rw-r--r--Tests/RunCMake/cmake_language/call_message.cmake2
-rw-r--r--Tests/RunCMake/cmake_language/call_no_parameters-stderr.txt2
-rw-r--r--Tests/RunCMake/cmake_language/defer_call-stderr.txt15
-rw-r--r--Tests/RunCMake/cmake_language/defer_call-stdout.txt8
-rw-r--r--Tests/RunCMake/cmake_language/defer_call.cmake12
-rw-r--r--Tests/RunCMake/cmake_language/defer_call/CMakeLists.txt11
-rw-r--r--Tests/RunCMake/cmake_language/defer_call/include.cmake1
-rw-r--r--Tests/RunCMake/cmake_language/defer_call_add_subdirectory-result.txt (renamed from Tests/RunCMake/FPHSA/range_empty-1-result.txt)0
-rw-r--r--Tests/RunCMake/cmake_language/defer_call_add_subdirectory-stderr.txt9
-rw-r--r--Tests/RunCMake/cmake_language/defer_call_add_subdirectory.cmake2
-rw-r--r--Tests/RunCMake/cmake_language/defer_call_add_subdirectory/CMakeLists.txt0
-rw-r--r--Tests/RunCMake/cmake_language/defer_call_enable_language-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/defer_call_enable_language-stderr.txt9
-rw-r--r--Tests/RunCMake/cmake_language/defer_call_enable_language.cmake2
-rw-r--r--Tests/RunCMake/cmake_language/defer_call_error-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/defer_call_error-stderr.txt9
-rw-r--r--Tests/RunCMake/cmake_language/defer_call_error.cmake3
-rw-r--r--Tests/RunCMake/cmake_language/defer_call_error/CMakeLists.txt2
-rw-r--r--Tests/RunCMake/cmake_language/defer_call_ids-stdout.txt13
-rw-r--r--Tests/RunCMake/cmake_language/defer_call_ids.cmake14
-rw-r--r--Tests/RunCMake/cmake_language/defer_call_invalid_command-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/defer_call_invalid_command-stderr.txt4
-rw-r--r--Tests/RunCMake/cmake_language/defer_call_invalid_command.cmake1
-rw-r--r--Tests/RunCMake/cmake_language/defer_call_invalid_directory-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/defer_call_invalid_directory-stderr.txt9
-rw-r--r--Tests/RunCMake/cmake_language/defer_call_invalid_directory.cmake2
-rw-r--r--Tests/RunCMake/cmake_language/defer_call_invalid_directory/CMakeLists.txt0
-rw-r--r--Tests/RunCMake/cmake_language/defer_call_missing_directory-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/defer_call_missing_directory-stderr.txt9
-rw-r--r--Tests/RunCMake/cmake_language/defer_call_missing_directory.cmake1
-rw-r--r--Tests/RunCMake/cmake_language/defer_call_policy_PUSH-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/defer_call_policy_PUSH-stderr.txt2
-rw-r--r--Tests/RunCMake/cmake_language/defer_call_policy_PUSH.cmake1
-rw-r--r--Tests/RunCMake/cmake_language/defer_call_syntax_error-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/defer_call_syntax_error-stderr.txt13
-rw-r--r--Tests/RunCMake/cmake_language/defer_call_syntax_error.cmake2
-rw-r--r--Tests/RunCMake/cmake_language/defer_call_trace-stderr.txt8
-rw-r--r--Tests/RunCMake/cmake_language/defer_call_trace.cmake3
-rw-r--r--Tests/RunCMake/cmake_language/defer_call_trace_json-stderr.txt5
-rw-r--r--Tests/RunCMake/cmake_language/defer_call_trace_json.cmake3
-rw-r--r--Tests/RunCMake/cmake_language/defer_cancel_call_id-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/defer_cancel_call_id-stderr.txt4
-rw-r--r--Tests/RunCMake/cmake_language/defer_cancel_call_id.cmake1
-rw-r--r--Tests/RunCMake/cmake_language/defer_cancel_call_id_var-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/defer_cancel_call_id_var-stderr.txt4
-rw-r--r--Tests/RunCMake/cmake_language/defer_cancel_call_id_var.cmake1
-rw-r--r--Tests/RunCMake/cmake_language/defer_cancel_call_invalid_directory-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/defer_cancel_call_invalid_directory-stderr.txt9
-rw-r--r--Tests/RunCMake/cmake_language/defer_cancel_call_invalid_directory.cmake2
-rw-r--r--Tests/RunCMake/cmake_language/defer_cancel_call_invalid_directory/CMakeLists.txt0
-rw-r--r--Tests/RunCMake/cmake_language/defer_cancel_call_unknown_argument-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/defer_cancel_call_unknown_argument-stderr.txt6
-rw-r--r--Tests/RunCMake/cmake_language/defer_cancel_call_unknown_argument.cmake1
-rw-r--r--Tests/RunCMake/cmake_language/defer_directory_empty-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/defer_directory_empty-stderr.txt4
-rw-r--r--Tests/RunCMake/cmake_language/defer_directory_empty.cmake1
-rw-r--r--Tests/RunCMake/cmake_language/defer_directory_missing-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/defer_directory_missing-stderr.txt4
-rw-r--r--Tests/RunCMake/cmake_language/defer_directory_missing.cmake1
-rw-r--r--Tests/RunCMake/cmake_language/defer_directory_multiple-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/defer_directory_multiple-stderr.txt4
-rw-r--r--Tests/RunCMake/cmake_language/defer_directory_multiple.cmake1
-rw-r--r--Tests/RunCMake/cmake_language/defer_get_call_id-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/defer_get_call_id-stderr.txt4
-rw-r--r--Tests/RunCMake/cmake_language/defer_get_call_id.cmake1
-rw-r--r--Tests/RunCMake/cmake_language/defer_get_call_id_empty-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/defer_get_call_id_empty-stderr.txt4
-rw-r--r--Tests/RunCMake/cmake_language/defer_get_call_id_empty.cmake1
-rw-r--r--Tests/RunCMake/cmake_language/defer_get_call_id_var-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/defer_get_call_id_var-stderr.txt4
-rw-r--r--Tests/RunCMake/cmake_language/defer_get_call_id_var.cmake1
-rw-r--r--Tests/RunCMake/cmake_language/defer_get_call_ids_id-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/defer_get_call_ids_id-stderr.txt4
-rw-r--r--Tests/RunCMake/cmake_language/defer_get_call_ids_id.cmake1
-rw-r--r--Tests/RunCMake/cmake_language/defer_get_call_ids_id_var-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/defer_get_call_ids_id_var-stderr.txt4
-rw-r--r--Tests/RunCMake/cmake_language/defer_get_call_ids_id_var.cmake1
-rw-r--r--Tests/RunCMake/cmake_language/defer_get_call_ids_invalid_directory-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/defer_get_call_ids_invalid_directory-stderr.txt9
-rw-r--r--Tests/RunCMake/cmake_language/defer_get_call_ids_invalid_directory.cmake2
-rw-r--r--Tests/RunCMake/cmake_language/defer_get_call_ids_invalid_directory/CMakeLists.txt0
-rw-r--r--Tests/RunCMake/cmake_language/defer_get_call_ids_missing_var-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/defer_get_call_ids_missing_var-stderr.txt4
-rw-r--r--Tests/RunCMake/cmake_language/defer_get_call_ids_missing_var.cmake1
-rw-r--r--Tests/RunCMake/cmake_language/defer_get_call_ids_too_many_args-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/defer_get_call_ids_too_many_args-stderr.txt4
-rw-r--r--Tests/RunCMake/cmake_language/defer_get_call_ids_too_many_args.cmake1
-rw-r--r--Tests/RunCMake/cmake_language/defer_get_call_missing_id-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/defer_get_call_missing_id-stderr.txt4
-rw-r--r--Tests/RunCMake/cmake_language/defer_get_call_missing_id.cmake1
-rw-r--r--Tests/RunCMake/cmake_language/defer_get_call_missing_var-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/defer_get_call_missing_var-stderr.txt4
-rw-r--r--Tests/RunCMake/cmake_language/defer_get_call_missing_var.cmake1
-rw-r--r--Tests/RunCMake/cmake_language/defer_get_call_too_many_args-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/defer_get_call_too_many_args-stderr.txt4
-rw-r--r--Tests/RunCMake/cmake_language/defer_get_call_too_many_args.cmake1
-rw-r--r--Tests/RunCMake/cmake_language/defer_get_call_unknown_argument-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/defer_get_call_unknown_argument-stderr.txt6
-rw-r--r--Tests/RunCMake/cmake_language/defer_get_call_unknown_argument.cmake1
-rw-r--r--Tests/RunCMake/cmake_language/defer_id_empty-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/defer_id_empty-stderr.txt4
-rw-r--r--Tests/RunCMake/cmake_language/defer_id_empty.cmake1
-rw-r--r--Tests/RunCMake/cmake_language/defer_id_missing-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/defer_id_missing-stderr.txt4
-rw-r--r--Tests/RunCMake/cmake_language/defer_id_missing.cmake1
-rw-r--r--Tests/RunCMake/cmake_language/defer_id_multiple-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/defer_id_multiple-stderr.txt4
-rw-r--r--Tests/RunCMake/cmake_language/defer_id_multiple.cmake1
-rw-r--r--Tests/RunCMake/cmake_language/defer_id_var_empty-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/defer_id_var_empty-stderr.txt4
-rw-r--r--Tests/RunCMake/cmake_language/defer_id_var_empty.cmake1
-rw-r--r--Tests/RunCMake/cmake_language/defer_id_var_missing-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/defer_id_var_missing-stderr.txt4
-rw-r--r--Tests/RunCMake/cmake_language/defer_id_var_missing.cmake1
-rw-r--r--Tests/RunCMake/cmake_language/defer_id_var_multiple-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/defer_id_var_multiple-stderr.txt4
-rw-r--r--Tests/RunCMake/cmake_language/defer_id_var_multiple.cmake1
-rw-r--r--Tests/RunCMake/cmake_language/defer_missing_arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/defer_missing_arg-stderr.txt4
-rw-r--r--Tests/RunCMake/cmake_language/defer_missing_arg.cmake1
-rw-r--r--Tests/RunCMake/cmake_language/defer_missing_call-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/defer_missing_call-stderr.txt4
-rw-r--r--Tests/RunCMake/cmake_language/defer_missing_call.cmake1
-rw-r--r--Tests/RunCMake/cmake_language/defer_unknown_option-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/defer_unknown_option-stderr.txt6
-rw-r--r--Tests/RunCMake/cmake_language/defer_unknown_option.cmake1
-rw-r--r--Tests/RunCMake/cmake_language/no_parameters-stderr.txt2
-rw-r--r--Tests/RunCMake/ctest_build/BuildCommandFailure-check.cmake12
-rw-r--r--Tests/RunCMake/ctest_build/BuildCommandFailure-result.txt1
-rw-r--r--Tests/RunCMake/ctest_build/BuildCommandFailure-stderr.txt1
-rw-r--r--Tests/RunCMake/ctest_build/RunCMakeTest.cmake6
-rw-r--r--Tests/RunCMake/fake_build_command.c6
-rw-r--r--Tests/RunCMake/find_package/EmptyVersionRange-result.txt1
-rw-r--r--Tests/RunCMake/find_package/EmptyVersionRange-stderr.txt10
-rw-r--r--Tests/RunCMake/find_package/EmptyVersionRange.cmake3
-rw-r--r--Tests/RunCMake/find_package/FindVersionRange.cmake22
-rw-r--r--Tests/RunCMake/find_package/RunCMakeTest.cmake2
-rw-r--r--Tests/RunCMake/find_package/VersionRange.cmake5
-rw-r--r--Tests/RunCMake/find_package/VersionRange2.cmake5
-rw-r--r--Tests/RunCMake/find_package/VersionRange3.cmake5
-rw-r--r--Tests/RunCMake/find_package/VersionRange4.cmake39
-rw-r--r--Utilities/cmlibuv/CMakeLists.txt18
-rwxr-xr-xbootstrap4
291 files changed, 4043 insertions, 1225 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index f4ebb02..c4c14bf 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -12,9 +12,9 @@ include:
- local: .gitlab/upload.yml
stages:
+ - prep
- build
- test
- - package
- test-ext
- upload
@@ -34,6 +34,35 @@ stages:
# - dependency/needs jobs for required jobs
################################################################################
+# Prep jobs
+
+prep:source:
+ extends:
+ - .linux_prep_source
+ - .cmake_prep_source_linux
+ - .linux_builder_tags
+ - .cmake_release_artifacts
+ - .run_only_for_package
+
+prep:doc:
+ extends:
+ - .fedora31_sphinx_package
+ - .cmake_prep_doc_linux
+ - .linux_builder_tags_qt
+ - .cmake_doc_artifacts
+ - .run_only_for_package
+
+upload:source:
+ extends:
+ - .rsync_upload
+ - .run_only_for_package
+ dependencies:
+ - prep:source
+ needs:
+ - prep:source
+ variables:
+ RSYNC_DESTINATION: dev
+
# Lint builds
build:debian10-iwyu:
@@ -56,14 +85,9 @@ build:fedora31-sphinx:
- .cmake_build_linux
- .linux_builder_tags_qt
- .run_automatically
-
-build:fedora31-sphinx-package:
- extends:
- - .fedora31_sphinx_package
- - .cmake_build_linux
- - .linux_builder_tags_qt
- - .cmake_doc_artifacts
- - .run_only_for_package
+ variables:
+ CMAKE_CI_JOB_CONTINUOUS: "true"
+ CMAKE_CI_JOB_HELP: "true"
# Linux builds
@@ -80,7 +104,7 @@ test:fedora31-makefiles:
- .fedora31_makefiles
- .cmake_test_linux_package
- .linux_builder_tags_qt
- - .run_automatically
+ - .run_dependent
dependencies:
- build:centos6-release
needs:
@@ -91,7 +115,7 @@ test:cuda10.2-nvidia:
- .cuda10.2_nvidia
- .cmake_test_linux_package
- .linux_builder_tags_cuda
- - .run_automatically
+ - .run_dependent
dependencies:
- build:centos6-release
needs:
@@ -111,7 +135,7 @@ test:fedora31-ninja:
- .cmake_test_linux
- .linux_builder_tags_x11
- .cmake_test_artifacts
- - .run_automatically
+ - .run_dependent
dependencies:
- build:fedora31-ninja
needs:
@@ -122,7 +146,7 @@ test:fedora31-ninja-multi:
- .fedora31_ninja_multi
- .cmake_test_linux_external
- .linux_builder_tags_qt
- - .run_automatically
+ - .run_dependent
dependencies:
- test:fedora31-ninja
needs:
@@ -144,7 +168,7 @@ test:macos-ninja:
- .cmake_test_macos
- .cmake_test_artifacts
- .macos_builder_tags
- - .run_automatically
+ - .run_dependent
dependencies:
- build:macos-ninja
needs:
@@ -163,7 +187,7 @@ test:macos-makefiles:
- .macos_makefiles
- .cmake_test_macos
- .macos_builder_tags
- - .run_automatically
+ - .run_dependent
dependencies:
- build:macos-makefiles
needs:
@@ -174,13 +198,13 @@ test:macos-xcode:
- .macos_xcode
- .cmake_test_macos_external
- .macos_builder_ext_tags
- - .run_automatically
+ - .run_dependent
dependencies:
- test:macos-ninja
needs:
- test:macos-ninja
-package:macos:
+build:macos-package:
extends:
- .macos_package
- .cmake_build_macos_package
@@ -188,18 +212,18 @@ package:macos:
- .macos_builder_tags_package
- .run_only_for_package
dependencies:
- - build:fedora31-sphinx-package
+ - prep:doc
needs:
- - build:fedora31-sphinx-package
+ - prep:doc
upload:macos:
extends:
- .rsync_upload
- .run_only_for_package
dependencies:
- - package:macos
+ - build:macos-package
needs:
- - package:macos
+ - build:macos-package
variables:
RSYNC_DESTINATION: dev
@@ -219,7 +243,7 @@ test:windows-vs2019-x64-ninja:
- .cmake_test_windows
- .windows_builder_tags
- .cmake_test_artifacts
- - .run_automatically
+ - .run_dependent
dependencies:
- build:windows-vs2019-x64-ninja
needs:
@@ -230,7 +254,7 @@ test:windows-vs2019-x64:
- .windows_vs2019_x64
- .cmake_test_windows_external
- .windows_builder_ext_tags
- - .run_automatically
+ - .run_dependent
dependencies:
- test:windows-vs2019-x64-ninja
needs:
diff --git a/.gitlab/artifacts.yml b/.gitlab/artifacts.yml
index f1c0c7e..1c24003 100644
--- a/.gitlab/artifacts.yml
+++ b/.gitlab/artifacts.yml
@@ -74,6 +74,9 @@
# Any packages made.
- build/cmake-*-Linux-x86_64.*
- build/cmake-*-Darwin-x86_64.*
+ # Any source packages made.
+ - build/cmake-*.tar.gz
+ - build/cmake-*.zip
.cmake_test_artifacts:
artifacts:
diff --git a/.gitlab/ci/cmake_version.cmake b/.gitlab/ci/cmake_version.cmake
new file mode 100644
index 0000000..ef9f7f2
--- /dev/null
+++ b/.gitlab/ci/cmake_version.cmake
@@ -0,0 +1,3 @@
+get_filename_component(CMake_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../.." ABSOLUTE)
+include("${CMake_SOURCE_DIR}/Source/CMakeVersion.cmake")
+message(STATUS ${CMake_VERSION})
diff --git a/.gitlab/ci/cmake_version.sh b/.gitlab/ci/cmake_version.sh
new file mode 100755
index 0000000..03b1614
--- /dev/null
+++ b/.gitlab/ci/cmake_version.sh
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+cmake -P "${BASH_SOURCE%/*}/cmake_version.cmake" | cut -d ' ' -f 2
diff --git a/.gitlab/ci/configure_fedora31_ninja.cmake b/.gitlab/ci/configure_fedora31_ninja.cmake
index 2743412..ea429c1 100644
--- a/.gitlab/ci/configure_fedora31_ninja.cmake
+++ b/.gitlab/ci/configure_fedora31_ninja.cmake
@@ -1,3 +1,7 @@
set(CMake_TEST_ISPC "ON" CACHE STRING "")
set(CMake_TEST_GUI "ON" CACHE BOOL "")
+
+# Cover compilation with C++11 only and not higher standards.
+set(CMAKE_CXX_STANDARD "11" CACHE STRING "")
+
include("${CMAKE_CURRENT_LIST_DIR}/configure_fedora31_common.cmake")
diff --git a/.gitlab/ci/ctest_test.cmake b/.gitlab/ci/ctest_test.cmake
index 569139d..08ef18f 100644
--- a/.gitlab/ci/ctest_test.cmake
+++ b/.gitlab/ci/ctest_test.cmake
@@ -10,6 +10,11 @@ ctest_start(APPEND)
include(ProcessorCount)
ProcessorCount(nproc)
+if (NOT "$ENV{CTEST_MAX_PARALLELISM}" STREQUAL "")
+ if (nproc GREATER "$ENV{CTEST_MAX_PARALLELISM}")
+ set(nproc "$ENV{CTEST_MAX_PARALLELISM}")
+ endif ()
+endif ()
include("${CMAKE_CURRENT_LIST_DIR}/ctest_exclusions.cmake")
ctest_test(
diff --git a/.gitlab/ci/gitlab_ci.cmake b/.gitlab/ci/gitlab_ci.cmake
index 7bd9300..7e5a7ab 100644
--- a/.gitlab/ci/gitlab_ci.cmake
+++ b/.gitlab/ci/gitlab_ci.cmake
@@ -49,6 +49,12 @@ endif ()
set(ctest_track "Experimental")
if (NOT "$ENV{CI_MERGE_REQUEST_ID}" STREQUAL "")
set(ctest_track "merge-requests")
+elseif (NOT "$ENV{CMAKE_CI_PROJECT_CONTINUOUS_BRANCH}" STREQUAL "" AND "$ENV{CMAKE_CI_PROJECT_CONTINUOUS_BRANCH}" STREQUAL "$ENV{CI_COMMIT_BRANCH}" AND NOT "$ENV{CMAKE_CI_JOB_CONTINUOUS}" STREQUAL "")
+ if (NOT "$ENV{CMAKE_CI_JOB_HELP}" STREQUAL "")
+ set(ctest_track "Continuous Help")
+ else()
+ set(ctest_track "Continuous")
+ endif()
elseif ("$ENV{CI_PROJECT_PATH}" STREQUAL "cmake/cmake")
if ("$ENV{CI_COMMIT_REF_NAME}" STREQUAL "master")
set(ctest_track "master")
diff --git a/.gitlab/os-linux.yml b/.gitlab/os-linux.yml
index 75f8156..74b2de7 100644
--- a/.gitlab/os-linux.yml
+++ b/.gitlab/os-linux.yml
@@ -11,6 +11,12 @@
GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci"
LAUNCHER: "scl enable devtoolset-6 rh-python36 --"
+.linux_prep_source:
+ image: "fedora:32"
+
+ variables:
+ GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci"
+
### Debian
.debian10:
@@ -143,6 +149,29 @@
- cmake --version
- ninja --version
+.cmake_prep_source_linux:
+ stage: prep
+
+ script:
+ - *before_script_linux
+ - dnf install --setopt=install_weak_deps=False -y git-core
+ - v="$(.gitlab/ci/cmake_version.sh)"
+ - mkdir -p build/
+ - git archive --format=tgz "--prefix=cmake-$v/" -o "build/cmake-$v.tar.gz" HEAD
+ - git -c core.autocrlf=true -c core.eol=crlf archive --format=zip --prefix="cmake-$v/" -o "build/cmake-$v.zip" HEAD
+
+ interruptible: true
+
+.cmake_prep_doc_linux:
+ stage: prep
+
+ script:
+ - *before_script_linux
+ - "$LAUNCHER ctest -VV -S .gitlab/ci/ctest_configure.cmake"
+ - "$LAUNCHER ctest -VV -S .gitlab/ci/ctest_build.cmake"
+
+ interruptible: true
+
.cmake_build_linux:
stage: build
diff --git a/.gitlab/os-macos.yml b/.gitlab/os-macos.yml
index 96ec264..a500d36 100644
--- a/.gitlab/os-macos.yml
+++ b/.gitlab/os-macos.yml
@@ -8,6 +8,8 @@
# TODO: Factor this out so that each job selects the Xcode version to
# use so that different versions can be tested in a single pipeline.
DEVELOPER_DIR: "/Applications/Xcode-11.7.app/Contents/Developer"
+ # Avoid conflicting with other projects running on the same machine.
+ SCCACHE_SERVER_PORT: 4227
### Build and test
@@ -109,7 +111,7 @@
interruptible: true
.cmake_build_macos_package:
- stage: package
+ stage: build
script:
- *before_script_macos
diff --git a/.gitlab/os-windows.yml b/.gitlab/os-windows.yml
index 63b8758..61a2018 100644
--- a/.gitlab/os-windows.yml
+++ b/.gitlab/os-windows.yml
@@ -5,6 +5,8 @@
.windows:
variables:
GIT_CLONE_PATH: "$CI_BUILDS_DIR\\cmake ci ext\\$CI_CONCURRENT_ID"
+ # Avoid conflicting with other projects running on the same machine.
+ SCCACHE_SERVER_PORT: 4227
### Build and test
diff --git a/.gitlab/rules.yml b/.gitlab/rules.yml
index 1803e79..1edfd97 100644
--- a/.gitlab/rules.yml
+++ b/.gitlab/rules.yml
@@ -4,6 +4,9 @@
rules:
- if: '$CMAKE_CI_PACKAGE == "true"'
when: never
+ - if: '($CMAKE_CI_PROJECT_CONTINUOUS_BRANCH != "" && $CI_COMMIT_BRANCH == $CMAKE_CI_PROJECT_CONTINUOUS_BRANCH && $CMAKE_CI_JOB_CONTINUOUS == "true")'
+ when: delayed
+ start_in: 5 minutes
- if: '$CI_MERGE_REQUEST_ID'
when: manual
- if: '$CI_PROJECT_PATH == "cmake/cmake"'
@@ -15,6 +18,18 @@
rules:
- if: '$CMAKE_CI_PACKAGE == "true"'
when: never
+ - if: '($CMAKE_CI_PROJECT_CONTINUOUS_BRANCH != "" && $CI_COMMIT_BRANCH == $CMAKE_CI_PROJECT_CONTINUOUS_BRANCH && $CMAKE_CI_JOB_CONTINUOUS == "true")'
+ when: on_success
+ - if: '$CI_MERGE_REQUEST_ID'
+ when: on_success
+ - if: '$CI_PROJECT_PATH == "cmake/cmake"'
+ when: on_success
+ - when: never
+
+.run_dependent:
+ rules:
+ - if: '$CMAKE_CI_PACKAGE == "true"'
+ when: never
- if: '$CI_MERGE_REQUEST_ID'
when: on_success
- if: '$CI_PROJECT_PATH == "cmake/cmake"'
diff --git a/Help/command/cmake_language.rst b/Help/command/cmake_language.rst
index 9e98d79..00e1a69 100644
--- a/Help/command/cmake_language.rst
+++ b/Help/command/cmake_language.rst
@@ -10,8 +10,9 @@ Synopsis
.. parsed-literal::
- cmake_language(`CALL`_ <command> [<args>...])
+ cmake_language(`CALL`_ <command> [<arg>...])
cmake_language(`EVAL`_ CODE <code>...)
+ cmake_language(`DEFER`_ <options>... CALL <command> [<arg>...])
Introduction
^^^^^^^^^^^^
@@ -28,7 +29,7 @@ Calling Commands
.. code-block:: cmake
- cmake_language(CALL <command> [<args>...])
+ cmake_language(CALL <command> [<arg>...])
Calls the named ``<command>`` with the given arguments (if any).
For example, the code:
@@ -99,3 +100,121 @@ is equivalent to
)
include(${CMAKE_CURRENT_BINARY_DIR}/eval.cmake)
+
+Deferring Calls
+^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.19
+
+.. _DEFER:
+
+.. code-block:: cmake
+
+ cmake_language(DEFER <options>... CALL <command> [<arg>...])
+
+Schedules a call to the named ``<command>`` with the given arguments (if any)
+to occur at a later time. By default, deferred calls are executed as if
+written at the end of the current directory's ``CMakeLists.txt`` file,
+except that they run even after a :command:`return` call. Variable
+references in arguments are evaluated at the time the deferred call is
+executed.
+
+The options are:
+
+``DIRECTORY <dir>``
+ Schedule the call for the end of the given directory instead of the
+ current directory. The ``<dir>`` may reference either a source
+ directory or its corresponding binary directory. Relative paths are
+ treated as relative to the current source directory.
+
+ The given directory must be known to CMake, being either the top-level
+ directory or one added by :command:`add_subdirectory`. Furthermore,
+ the given directory must not yet be finished processing. This means
+ it can be the current directory or one of its ancestors.
+
+``ID <id>``
+ Specify an identification for the deferred call.
+ The id may not be empty and may not begin in a capital letter ``A-Z``.
+ The id may begin in a ``_`` only if it was generated by another call
+ that used ``ID_VAR`` to get the id.
+
+``ID_VAR <var>``
+ Sepcify a variable in which to store the identification for the
+ deferred call. If ``ID <id>`` is not given, a new identification
+ will be generated starting in a ``_``.
+
+The currently scheduled list of deferred calls may be retrieved:
+
+.. code-block:: cmake
+
+ cmake_language(DEFER [DIRECTORY <dir>] GET_CALL_IDS <var>)
+
+This will store in ``<var>`` a :ref:`Semicolon-separated list <CMake Language
+Lists>` of deferred call ids.
+
+Details of a specific call may be retrieved from its id:
+
+.. code-block:: cmake
+
+ cmake_language(DEFER [DIRECTORY <dir>] GET_CALL <id> <var>)
+
+This will store in ``<var>`` a :ref:`Semicolon-separated list <CMake Language
+Lists>` in which the first element is the name of the command to be
+called, and the remaining elements are its unevaluated arguments (any
+contained ``;`` characters are included literally and cannot be distinguished
+from multiple arguments). If multiple calls are scheduled with the same id,
+this retrieves the first one. If no call is scheduled with the given id,
+this stores an empty string in the variable.
+
+Deferred calls may be canceled by their id:
+
+.. code-block:: cmake
+
+ cmake_language(DEFER [DIRECTORY <dir>] CANCEL_CALL <id>...)
+
+This cancels all deferred calls matching any of the given ids.
+Unknown ids are silently ignored.
+
+Deferred Call Examples
+""""""""""""""""""""""
+
+For example, the code:
+
+.. code-block:: cmake
+
+ cmake_language(DEFER CALL message "${deferred_message}")
+ cmake_language(DEFER ID_VAR id CALL message "Cancelled Message")
+ cmake_language(DEFER CANCEL_CALL ${id})
+ message("Immediate Message")
+ set(deferred_message "Deferred Message")
+
+prints::
+
+ Immediate Message
+ Deferred Message
+
+The ``Cancelled Message`` is never printed because its command is
+cancelled. The ``deferred_message`` variable reference is not evaluated
+until the call site, so it can be set after the deferred call is scheduled.
+
+In order to evaluate variable references immediately when scheduling a
+deferred call, wrap it using ``cmake_language(EVAL)``. However, note that
+arguments will be re-evaluated in the deferred call, though that can be
+avoided by using bracket arguments. For example:
+
+.. code-block:: cmake
+
+ set(deferred_message "Deferred Message 1")
+ set(re_evaluated [[${deferred_message}]])
+ cmake_language(EVAL CODE "
+ cmake_language(DEFER CALL message [[${deferred_message}]])
+ cmake_language(DEFER CALL message \"${re_evaluated}\")
+ ")
+ message("Immediate Message")
+ set(deferred_message "Deferred Message 2")
+
+also prints::
+
+ Immediate Message
+ Deferred Message 1
+ Deferred Message 2
diff --git a/Help/command/return.rst b/Help/command/return.rst
index 830992c..ec009d8 100644
--- a/Help/command/return.rst
+++ b/Help/command/return.rst
@@ -12,6 +12,7 @@ encountered in an included file (via :command:`include` or
:command:`find_package`), it causes processing of the current file to stop
and control is returned to the including file. If it is encountered in a
file which is not included by another file, e.g. a ``CMakeLists.txt``,
+deferred calls scheduled by :command:`cmake_language(DEFER)` are invoked and
control is returned to the parent directory if there is one. If return is
called in a function, control is returned to the caller of the function.
diff --git a/Help/guide/importing-exporting/index.rst b/Help/guide/importing-exporting/index.rst
index b0cfb71..2e6e06d 100644
--- a/Help/guide/importing-exporting/index.rst
+++ b/Help/guide/importing-exporting/index.rst
@@ -1,10 +1,13 @@
-Importing and Exporting Targets
-*******************************
+Importing and Exporting Guide
+*****************************
.. only:: html
.. contents::
+Introduction
+============
+
In this guide, we will present the concept of :prop_tgt:`IMPORTED` targets
and demonstrate how to import existing executable or library files from disk
into a CMake project. We will then show how CMake supports exporting targets
diff --git a/Help/guide/tutorial/index.rst b/Help/guide/tutorial/index.rst
index 665d123..4b09e53 100644
--- a/Help/guide/tutorial/index.rst
+++ b/Help/guide/tutorial/index.rst
@@ -5,6 +5,9 @@ CMake Tutorial
.. contents::
+Introduction
+============
+
The CMake tutorial provides a step-by-step guide that covers common build
system issues that CMake helps address. Seeing how various topics all
work together in an example project can be very helpful. The tutorial
diff --git a/Help/manual/VS-Choose-Arch.png b/Help/guide/user-interaction/VS-Choose-Arch.png
index 816b0f4..816b0f4 100644
--- a/Help/manual/VS-Choose-Arch.png
+++ b/Help/guide/user-interaction/VS-Choose-Arch.png
Binary files differ
diff --git a/Help/guide/user-interaction/index.rst b/Help/guide/user-interaction/index.rst
index c724b6f..2d8ed29 100644
--- a/Help/guide/user-interaction/index.rst
+++ b/Help/guide/user-interaction/index.rst
@@ -85,7 +85,7 @@ The source and binary directories must first be
populated. It is always advised to use different
directories for the source and the build.
-.. image:: /guide/user-interaction/GUI-Source-Binary.png
+.. image:: GUI-Source-Binary.png
:alt: Choosing source and binary directories
Generating a Buildsystem
@@ -246,19 +246,19 @@ Choosing a generator in cmake-gui
The "Configure" button triggers a new dialog to
select the CMake generator to use.
-.. image:: /guide/user-interaction/GUI-Configure-Dialog.png
+.. image:: GUI-Configure-Dialog.png
:alt: Configuring a generator
All generators available on the command line are also
available in :manual:`cmake-gui(1)`.
-.. image:: /guide/user-interaction/GUI-Choose-Generator.png
+.. image:: GUI-Choose-Generator.png
:alt: Choosing a generator
When choosing a Visual Studio generator, further options
are available to set an architecture to generate for.
-.. image:: /manual/VS-Choose-Arch.png
+.. image:: VS-Choose-Arch.png
:alt: Choosing an architecture for Visual Studio generators
.. _`Setting Build Variables`:
@@ -359,7 +359,7 @@ Variables may be set in the cmake-gui using the "Add Entry"
button. This triggers a new dialog to set the value of
the variable.
-.. image:: /guide/user-interaction/GUI-Add-Entry.png
+.. image:: GUI-Add-Entry.png
:alt: Editing a cache entry
The main view of the :manual:`cmake-gui(1)` user interface
diff --git a/Help/guide/using-dependencies/index.rst b/Help/guide/using-dependencies/index.rst
index 6fdcc55..f4d7845 100644
--- a/Help/guide/using-dependencies/index.rst
+++ b/Help/guide/using-dependencies/index.rst
@@ -31,7 +31,7 @@ See the :guide:`User Interaction Guide` for
more about setting cache entries.
Libraries providing Config-file packages
-----------------------------------------
+========================================
The most convenient way for a third-party to provide library
binaries for use with CMake is to provide
@@ -115,7 +115,7 @@ file, such as ``/opt/somepackage/lib/cmake/SomePackage/`` in
the above example.
Imported Targets from Packages
-------------------------------
+==============================
A third-party package which provides config-file packages may
also provide :ref:`Imported targets`. These will be
diff --git a/Help/manual/cmake-modules.7.rst b/Help/manual/cmake-modules.7.rst
index d364198..14af149 100644
--- a/Help/manual/cmake-modules.7.rst
+++ b/Help/manual/cmake-modules.7.rst
@@ -45,6 +45,7 @@ These modules are loaded using the :command:`include` command.
/module/CheckOBJCXXSourceRuns
/module/CheckPIESupported
/module/CheckPrototypeDefinition
+ /module/CheckCompilerFlag
/module/CheckSourceCompiles
/module/CheckSourceRuns
/module/CheckStructHasMember
diff --git a/Help/manual/cmake.1.rst b/Help/manual/cmake.1.rst
index c5e0aae..9850116 100644
--- a/Help/manual/cmake.1.rst
+++ b/Help/manual/cmake.1.rst
@@ -295,6 +295,11 @@ Options
``line``
The line in ``file`` of the function call.
+ ``defer``
+ Optional member that is present when the function call was deferred
+ by :command:`cmake_language(DEFER)`. If present, its value is a
+ string containing the deferred call ``<id>``.
+
``cmd``
The name of the function that was called.
@@ -317,7 +322,7 @@ Options
{
"version": {
"major": 1,
- "minor": 0
+ "minor": 1
}
}
diff --git a/Help/module/CheckCompilerFlag.rst b/Help/module/CheckCompilerFlag.rst
new file mode 100644
index 0000000..bcf19a8
--- /dev/null
+++ b/Help/module/CheckCompilerFlag.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CheckCompilerFlag.cmake
diff --git a/Help/release/dev/FindPython-version_range.rst b/Help/release/dev/FindPython-version_range.rst
new file mode 100644
index 0000000..06318b4
--- /dev/null
+++ b/Help/release/dev/FindPython-version_range.rst
@@ -0,0 +1,5 @@
+FindPython-version_range
+------------------------
+
+* The :module:`FindPython3`, :module:`FindPython2` and :module:`FindPython`
+ modules gained the capability to manage a version range.
diff --git a/Help/release/dev/check-source-modules.rst b/Help/release/dev/check-source-modules.rst
index 9a7785a..e6cccbe 100644
--- a/Help/release/dev/check-source-modules.rst
+++ b/Help/release/dev/check-source-modules.rst
@@ -8,3 +8,7 @@ check-source-modules
* The :module:`CheckSourceRuns` module has been added to
generalize :module:`CheckCSourceRuns` and
:module:`CheckCXXSourceRuns` to more languages.
+
+* The :module:`CheckCompilerFlag` module has been added to
+ generalize :module:`CheckCCompilerFlag` and
+ :module:`CheckCXXCompilerFlag` to more languages.
diff --git a/Help/release/dev/cmake-gui-environment.rst b/Help/release/dev/cmake-gui-environment.rst
new file mode 100644
index 0000000..1c8485e
--- /dev/null
+++ b/Help/release/dev/cmake-gui-environment.rst
@@ -0,0 +1,4 @@
+cmake-gui-environment
+---------------------
+
+* The :manual:`CMake GUI <cmake-gui(1)>` now has an environment variable editor.
diff --git a/Help/release/dev/cmake_language-DEFER.rst b/Help/release/dev/cmake_language-DEFER.rst
new file mode 100644
index 0000000..8bd0ee9
--- /dev/null
+++ b/Help/release/dev/cmake_language-DEFER.rst
@@ -0,0 +1,5 @@
+cmake_language-DEFER
+--------------------
+
+* The :command:`cmake_language` command gained a ``DEFER`` mode to
+ schedule command calls to occur at the end of processing a directory.
diff --git a/Help/variable/CMAKE_CURRENT_LIST_LINE.rst b/Help/variable/CMAKE_CURRENT_LIST_LINE.rst
index 60e8e26..7f839c2 100644
--- a/Help/variable/CMAKE_CURRENT_LIST_LINE.rst
+++ b/Help/variable/CMAKE_CURRENT_LIST_LINE.rst
@@ -5,3 +5,7 @@ The line number of the current file being processed.
This is the line number of the file currently being processed by
cmake.
+
+If CMake is currently processing deferred calls scheduled by
+the :command:`cmake_language(DEFER)` command, this variable
+evaluates to ``DEFERRED`` instead of a specific line number.
diff --git a/Help/variable/CMAKE_LANG_COMPILER_ID.rst b/Help/variable/CMAKE_LANG_COMPILER_ID.rst
index c495b71..99ff015 100644
--- a/Help/variable/CMAKE_LANG_COMPILER_ID.rst
+++ b/Help/variable/CMAKE_LANG_COMPILER_ID.rst
@@ -26,6 +26,7 @@ include:
IAR = IAR Systems (iar.com)
Intel = Intel Compiler (intel.com)
IntelDPCPP = Intel DPCPP Compiler (intel.com)
+ IntelClang = Intel Clang Compiler (intel.com)
MSVC = Microsoft Visual Studio (microsoft.com)
NVIDIA = NVIDIA CUDA Compiler (nvidia.com)
OpenWatcom = Open Watcom (openwatcom.org)
diff --git a/Modules/CMakeCompilerIdDetection.cmake b/Modules/CMakeCompilerIdDetection.cmake
index 176e768..26fb381 100644
--- a/Modules/CMakeCompilerIdDetection.cmake
+++ b/Modules/CMakeCompilerIdDetection.cmake
@@ -79,6 +79,7 @@ function(compiler_id_detection outvar lang)
AppleClang
ARMClang
IntelDPCPP
+ IntelClang
Clang
GNU
MSVC
diff --git a/Modules/CMakeGenericSystem.cmake b/Modules/CMakeGenericSystem.cmake
index 6f665a6..649b6f7 100644
--- a/Modules/CMakeGenericSystem.cmake
+++ b/Modules/CMakeGenericSystem.cmake
@@ -77,10 +77,14 @@ function(GetDefaultWindowsPrefixBase var)
#
if("${CMAKE_GENERATOR}" MATCHES "(Win64|IA64)")
set(arch_hint "x64")
+ elseif("${CMAKE_GENERATOR_PLATFORM}" MATCHES "x64")
+ set(arch_hint "x64")
elseif("${CMAKE_GENERATOR_PLATFORM}" MATCHES "ARM64")
set(arch_hint "ARM64")
elseif("${CMAKE_GENERATOR}" MATCHES "ARM")
set(arch_hint "ARM")
+ elseif("${CMAKE_GENERATOR_PLATFORM}" MATCHES "ARM")
+ set(arch_hint "ARM")
elseif("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8")
set(arch_hint "x64")
elseif("$ENV{LIB}" MATCHES "(amd64|ia64)")
diff --git a/Modules/CMakeOBJCInformation.cmake b/Modules/CMakeOBJCInformation.cmake
index b3da82d..d530191 100644
--- a/Modules/CMakeOBJCInformation.cmake
+++ b/Modules/CMakeOBJCInformation.cmake
@@ -170,7 +170,7 @@ endif()
# compile an Objective-C file into an object file
if(NOT CMAKE_OBJC_COMPILE_OBJECT)
set(CMAKE_OBJC_COMPILE_OBJECT
- "<CMAKE_OBJC_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -x objective-c -o <OBJECT> -c <SOURCE>")
+ "<CMAKE_OBJC_COMPILER> <DEFINES> <INCLUDES> -x objective-c <FLAGS> -o <OBJECT> -c <SOURCE>")
endif()
if(NOT CMAKE_OBJC_LINK_EXECUTABLE)
diff --git a/Modules/CMakeOBJCXXInformation.cmake b/Modules/CMakeOBJCXXInformation.cmake
index 4be9762..7a3b9d7 100644
--- a/Modules/CMakeOBJCXXInformation.cmake
+++ b/Modules/CMakeOBJCXXInformation.cmake
@@ -263,7 +263,7 @@ endif()
# compile an Objective-C++ file into an object file
if(NOT CMAKE_OBJCXX_COMPILE_OBJECT)
set(CMAKE_OBJCXX_COMPILE_OBJECT
- "<CMAKE_OBJCXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>")
+ "<CMAKE_OBJCXX_COMPILER> <DEFINES> <INCLUDES> -x objective-c++ <FLAGS> -o <OBJECT> -c <SOURCE>")
endif()
if(NOT CMAKE_OBJCXX_LINK_EXECUTABLE)
diff --git a/Modules/CheckCCompilerFlag.cmake b/Modules/CheckCCompilerFlag.cmake
index 1452b51..f835f29 100644
--- a/Modules/CheckCCompilerFlag.cmake
+++ b/Modules/CheckCCompilerFlag.cmake
@@ -34,24 +34,8 @@ effect or even a specific one is beyond the scope of this module.
include_guard(GLOBAL)
include(CheckCSourceCompiles)
-include(CMakeCheckCompilerFlagCommonPatterns)
-
-function(check_c_compiler_flag _flag _var)
- set(CMAKE_REQUIRED_DEFINITIONS "${_flag}")
-
- # Normalize locale during test compilation.
- set(_locale_vars LC_ALL LC_MESSAGES LANG)
- foreach(v IN LISTS _locale_vars)
- set(_locale_vars_saved_${v} "$ENV{${v}}")
- set(ENV{${v}} C)
- endforeach()
- check_compiler_flag_common_patterns(_common_patterns)
- check_c_source_compiles("int main(void) { return 0; }" ${_var}
- # Some compilers do not fail with a bad flag
- FAIL_REGEX "command line option .* is valid for .* but not for C" # GNU
- ${_common_patterns}
- )
- foreach(v IN LISTS _locale_vars)
- set(ENV{${v}} ${_locale_vars_saved_${v}})
- endforeach()
-endfunction()
+include(CheckCompilerFlag)
+
+macro (CHECK_C_COMPILER_FLAG _FLAG _RESULT)
+ check_compiler_flag(C "${_FLAG}" ${_RESULT})
+endmacro ()
diff --git a/Modules/CheckCXXCompilerFlag.cmake b/Modules/CheckCXXCompilerFlag.cmake
index 544e9ac..ce49ae3 100644
--- a/Modules/CheckCXXCompilerFlag.cmake
+++ b/Modules/CheckCXXCompilerFlag.cmake
@@ -34,24 +34,8 @@ effect or even a specific one is beyond the scope of this module.
include_guard(GLOBAL)
include(CheckCXXSourceCompiles)
-include(CMakeCheckCompilerFlagCommonPatterns)
-
-function(check_cxx_compiler_flag _flag _var)
- set(CMAKE_REQUIRED_DEFINITIONS "${_flag}")
-
- # Normalize locale during test compilation.
- set(_locale_vars LC_ALL LC_MESSAGES LANG)
- foreach(v IN LISTS _locale_vars)
- set(_locale_vars_saved_${v} "$ENV{${v}}")
- set(ENV{${v}} C)
- endforeach()
- check_compiler_flag_common_patterns(_common_patterns)
- check_cxx_source_compiles("int main() { return 0; }" ${_var}
- # Some compilers do not fail with a bad flag
- FAIL_REGEX "command line option .* is valid for .* but not for C\\\\+\\\\+" # GNU
- ${_common_patterns}
- )
- foreach(v IN LISTS _locale_vars)
- set(ENV{${v}} ${_locale_vars_saved_${v}})
- endforeach()
-endfunction()
+include(CheckCompilerFlag)
+
+macro (CHECK_CXX_COMPILER_FLAG _FLAG _RESULT)
+ check_compiler_flag(CXX "${_FLAG}" ${_RESULT})
+endmacro ()
diff --git a/Modules/CheckCompilerFlag.cmake b/Modules/CheckCompilerFlag.cmake
new file mode 100644
index 0000000..9223009
--- /dev/null
+++ b/Modules/CheckCompilerFlag.cmake
@@ -0,0 +1,105 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CheckCompilerFlag
+---------------------
+
+.. versionadded:: 3.19
+
+Check whether the compiler supports a given flag.
+
+.. command:: check_compiler_flag
+
+ .. code-block:: cmake
+
+ check_compiler_flag(<lang> <flag> <var>)
+
+Check that the ``<flag>`` is accepted by the compiler without a diagnostic.
+Stores the result in an internal cache entry named ``<var>``.
+
+This command temporarily sets the ``CMAKE_REQUIRED_DEFINITIONS`` variable
+and calls the ``check_source_compiles(<LANG>`` function from the
+:module:`CheckSourceCompiles` module. See documentation of that
+module for a listing of variables that can otherwise modify the build.
+
+A positive result from this check indicates only that the compiler did not
+issue a diagnostic message when given the flag. Whether the flag has any
+effect or even a specific one is beyond the scope of this module.
+
+.. note::
+ Since the :command:`try_compile` command forwards flags from variables
+ like :variable:`CMAKE_<LANG>_FLAGS <CMAKE_<LANG>_FLAGS>`, unknown flags
+ in such variables may cause a false negative for this check.
+#]=======================================================================]
+
+include_guard(GLOBAL)
+include(CheckSourceCompiles)
+include(CMakeCheckCompilerFlagCommonPatterns)
+
+cmake_policy(PUSH)
+cmake_policy(SET CMP0054 NEW) # if() quoted variables not dereferenced
+cmake_policy(SET CMP0057 NEW) # if() supports IN_LIST
+
+function(CHECK_COMPILER_FLAG _lang _flag _var)
+
+ if(_lang STREQUAL C)
+ set(_lang_src "int main(void) { return 0; }")
+ set(_lang_fail_regex FAIL_REGEX "command line option .* is valid for .* but not for C")
+ elseif(_lang STREQUAL CXX)
+ set(_lang_src "int main() { return 0; }")
+ set(_lang_fail_regex FAIL_REGEX "command line option .* is valid for .* but not for C\\+\\+")
+ elseif(_lang STREQUAL Fortran)
+ set(_lang_src " program test\n stop\n end program")
+ set(_lang_fail_regex FAIL_REGEX "command line option .* is valid for .* but not for Fortran")
+ elseif(_lang STREQUAL OBJC)
+ set(_lang_src [=[
+#ifndef __OBJC__
+# error "Not an Objective-C compiler"
+#endif
+int main(void) { return 0; }]=])
+ set(_lang_fail_regex FAIL_REGEX "command line option .* is valid for .* but not for Objective-C" # GNU
+ FAIL_REGEX "argument unused during compilation: .*") # Clang
+ elseif(_lang STREQUAL OBJCXX)
+ set(_lang_src [=[
+#ifndef __OBJC__
+# error "Not an Objective-C++ compiler"
+#endif
+int main(void) { return 0; }]=])
+ set(_lang_fail_regex FAIL_REGEX "command line option .* is valid for .* but not for Objective-C\\+\\+" # GNU
+ FAIL_REGEX "argument unused during compilation: .*") # Clang
+ else()
+ message (SEND_ERROR "check_compiler_flag: ${_lang}: unknown language.")
+ return()
+ endif()
+
+ get_property (_supported_languages GLOBAL PROPERTY ENABLED_LANGUAGES)
+ if (NOT _lang IN_LIST _supported_languages)
+ message (SEND_ERROR "check_compiler_flag: ${_lang}: needs to be enabled before use.")
+ return()
+ endif()
+
+ set(CMAKE_REQUIRED_DEFINITIONS ${_flag})
+
+ # Normalize locale during test compilation.
+ set(_locale_vars LC_ALL LC_MESSAGES LANG)
+ foreach(v IN LISTS _locale_vars)
+ set(_locale_vars_saved_${v} "$ENV{${v}}")
+ set(ENV{${v}} C)
+ endforeach()
+
+ check_compiler_flag_common_patterns(_common_patterns)
+ check_source_compiles(${_lang}
+ "${_lang_src}"
+ ${_var}
+ ${_lang_fail_regex}
+ ${_common_patterns}
+ )
+
+ foreach(v IN LISTS _locale_vars)
+ set(ENV{${v}} ${_locale_vars_saved_${v}})
+ endforeach()
+ set(${_var} "${${_var}}" PARENT_SCOPE)
+endfunction ()
+
+cmake_policy(POP)
diff --git a/Modules/CheckFortranCompilerFlag.cmake b/Modules/CheckFortranCompilerFlag.cmake
index b8fac97..0f5cf9a 100644
--- a/Modules/CheckFortranCompilerFlag.cmake
+++ b/Modules/CheckFortranCompilerFlag.cmake
@@ -36,30 +36,8 @@ effect or even a specific one is beyond the scope of this module.
include_guard(GLOBAL)
include(CheckFortranSourceCompiles)
-include(CMakeCheckCompilerFlagCommonPatterns)
+include(CheckCompilerFlag)
-macro (CHECK_Fortran_COMPILER_FLAG _FLAG _RESULT)
- set(SAFE_CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS}")
- set(CMAKE_REQUIRED_DEFINITIONS "${_FLAG}")
-
- # Normalize locale during test compilation.
- set(_CheckFortranCompilerFlag_LOCALE_VARS LC_ALL LC_MESSAGES LANG)
- foreach(v ${_CheckFortranCompilerFlag_LOCALE_VARS})
- set(_CheckFortranCompilerFlag_SAVED_${v} "$ENV{${v}}")
- set(ENV{${v}} C)
- endforeach()
- CHECK_COMPILER_FLAG_COMMON_PATTERNS(_CheckFortranCompilerFlag_COMMON_PATTERNS)
- CHECK_Fortran_SOURCE_COMPILES(" program test\n stop\n end program" ${_RESULT}
- # Some compilers do not fail with a bad flag
- FAIL_REGEX "command line option .* is valid for .* but not for Fortran" # GNU
- ${_CheckFortranCompilerFlag_COMMON_PATTERNS}
- )
- foreach(v ${_CheckFortranCompilerFlag_LOCALE_VARS})
- set(ENV{${v}} ${_CheckFortranCompilerFlag_SAVED_${v}})
- unset(_CheckFortranCompilerFlag_SAVED_${v})
- endforeach()
- unset(_CheckFortranCompilerFlag_LOCALE_VARS)
- unset(_CheckFortranCompilerFlag_COMMON_PATTERNS)
-
- set (CMAKE_REQUIRED_DEFINITIONS "${SAFE_CMAKE_REQUIRED_DEFINITIONS}")
+macro (CHECK_FORTRAN_COMPILER_FLAG _FLAG _RESULT)
+ check_compiler_flag(Fortran "${_FLAG}" ${_RESULT})
endmacro ()
diff --git a/Modules/CheckOBJCCompilerFlag.cmake b/Modules/CheckOBJCCompilerFlag.cmake
index a98f429..df9d724 100644
--- a/Modules/CheckOBJCCompilerFlag.cmake
+++ b/Modules/CheckOBJCCompilerFlag.cmake
@@ -36,31 +36,8 @@ effect or even a specific one is beyond the scope of this module.
include_guard(GLOBAL)
include(CheckOBJCSourceCompiles)
-include(CMakeCheckCompilerFlagCommonPatterns)
+include(CheckCompilerFlag)
macro (CHECK_OBJC_COMPILER_FLAG _FLAG _RESULT)
- set(SAFE_CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS}")
- set(CMAKE_REQUIRED_DEFINITIONS "${_FLAG}")
-
- # Normalize locale during test compilation.
- set(_CheckOBJCCompilerFlag_LOCALE_VARS LC_ALL LC_MESSAGES LANG)
- foreach(v ${_CheckOBJCCompilerFlag_LOCALE_VARS})
- set(_CheckOBJCCompilerFlag_SAVED_${v} "$ENV{${v}}")
- set(ENV{${v}} OBJC)
- endforeach()
- CHECK_COMPILER_FLAG_COMMON_PATTERNS(_CheckOBJCCompilerFlag_COMMON_PATTERNS)
- CHECK_OBJC_SOURCE_COMPILES("#ifndef __OBJC__\n# error \"Not an Objective-C compiler\"\n#endif\nint main(void) { return 0; }" ${_RESULT}
- # Some compilers do not fail with a bad flag
- FAIL_REGEX "command line option .* is valid for .* but not for Objective-C" # GNU
- FAIL_REGEX "argument unused during compilation: .*" # Clang
- ${_CheckOBJCCompilerFlag_COMMON_PATTERNS}
- )
- foreach(v ${_CheckOBJCCompilerFlag_LOCALE_VARS})
- set(ENV{${v}} ${_CheckOBJCCompilerFlag_SAVED_${v}})
- unset(_CheckOBJCCompilerFlag_SAVED_${v})
- endforeach()
- unset(_CheckOBJCCompilerFlag_LOCALE_VARS)
- unset(_CheckOBJCCompilerFlag_COMMON_PATTERNS)
-
- set (CMAKE_REQUIRED_DEFINITIONS "${SAFE_CMAKE_REQUIRED_DEFINITIONS}")
+ check_compiler_flag(OBJC "${_FLAG}" ${_RESULT})
endmacro ()
diff --git a/Modules/CheckOBJCXXCompilerFlag.cmake b/Modules/CheckOBJCXXCompilerFlag.cmake
index 7944ab0..6e01bcc 100644
--- a/Modules/CheckOBJCXXCompilerFlag.cmake
+++ b/Modules/CheckOBJCXXCompilerFlag.cmake
@@ -36,31 +36,8 @@ effect or even a specific one is beyond the scope of this module.
include_guard(GLOBAL)
include(CheckOBJCXXSourceCompiles)
-include(CMakeCheckCompilerFlagCommonPatterns)
+include(CheckCompilerFlag)
macro (CHECK_OBJCXX_COMPILER_FLAG _FLAG _RESULT)
- set(SAFE_CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS}")
- set(CMAKE_REQUIRED_DEFINITIONS "${_FLAG}")
-
- # Normalize locale during test compilation.
- set(_CheckOBJCXXCompilerFlag_LOCALE_VARS LC_ALL LC_MESSAGES LANG)
- foreach(v ${_CheckOBJCXXCompilerFlag_LOCALE_VARS})
- set(_CheckOBJCXXCompilerFlag_SAVED_${v} "$ENV{${v}}")
- set(ENV{${v}} OBJCXX)
- endforeach()
- CHECK_COMPILER_FLAG_COMMON_PATTERNS(_CheckOBJCXXCompilerFlag_COMMON_PATTERNS)
- CHECK_OBJCXX_SOURCE_COMPILES("#ifndef __OBJC__\n# error \"Not an Objective-C++ compiler\"\n#endif\nint main(void) { return 0; }" ${_RESULT}
- # Some compilers do not fail with a bad flag
- FAIL_REGEX "command line option .* is valid for .* but not for Objective-C\\\\+\\\\+" # GNU
- FAIL_REGEX "argument unused during compilation: .*" # Clang
- ${_CheckOBJCXXCompilerFlag_COMMON_PATTERNS}
- )
- foreach(v ${_CheckOBJCXXCompilerFlag_LOCALE_VARS})
- set(ENV{${v}} ${_CheckOBJCXXCompilerFlag_SAVED_${v}})
- unset(_CheckOBJCXXCompilerFlag_SAVED_${v})
- endforeach()
- unset(_CheckOBJCXXCompilerFlag_LOCALE_VARS)
- unset(_CheckOBJCXXCompilerFlag_COMMON_PATTERNS)
-
- set (CMAKE_REQUIRED_DEFINITIONS "${SAFE_CMAKE_REQUIRED_DEFINITIONS}")
+ check_compiler_flag(OBJCXX "${_FLAG}" ${_RESULT})
endmacro ()
diff --git a/Modules/Compiler/IntelClang-DetermineCompiler.cmake b/Modules/Compiler/IntelClang-DetermineCompiler.cmake
new file mode 100644
index 0000000..3544be3
--- /dev/null
+++ b/Modules/Compiler/IntelClang-DetermineCompiler.cmake
@@ -0,0 +1,7 @@
+
+set(_compiler_id_pp_test "defined(__clang__) && defined(__INTEL_CLANG_COMPILER)")
+
+include("${CMAKE_CURRENT_LIST_DIR}/Clang-DetermineCompilerInternal.cmake")
+
+string(APPEND _compiler_id_version_compute "
+# define @PREFIX@COMPILER_VERSION_TWEAK @MACRO_DEC@(__INTEL_CLANG_COMPILER)")
diff --git a/Modules/FindCUDA/select_compute_arch.cmake b/Modules/FindCUDA/select_compute_arch.cmake
index c11725d..9351288 100644
--- a/Modules/FindCUDA/select_compute_arch.cmake
+++ b/Modules/FindCUDA/select_compute_arch.cmake
@@ -7,7 +7,7 @@
# ARCH_AND_PTX : NAME | NUM.NUM | NUM.NUM(NUM.NUM) | NUM.NUM+PTX
# NAME: Fermi Kepler Maxwell Kepler+Tegra Kepler+Tesla Maxwell+Tegra Pascal Volta Turing Ampere
# NUM: Any number. Only those pairs are currently accepted by NVCC though:
-# 2.0 2.1 3.0 3.2 3.5 3.7 5.0 5.2 5.3 6.0 6.2 7.0 7.2 7.5 8.0
+# 2.0 2.1 3.0 3.2 3.5 3.7 5.0 5.2 5.3 6.0 6.2 7.0 7.2 7.5 8.0 8.6
# Returns LIST of flags to be added to CUDA_NVCC_FLAGS in ${out_variable}
# Additionally, sets ${out_variable}_readable to the resulting numeric list
# Example:
@@ -82,16 +82,26 @@ if(CUDA_VERSION VERSION_GREATER_EQUAL "10.0")
list(APPEND CUDA_ALL_GPU_ARCHITECTURES "7.5")
if(CUDA_VERSION VERSION_LESS "11.0")
- set(CUDA_LIMIT_GPU_ARCHITECTURE "8.0")
list(APPEND CUDA_COMMON_GPU_ARCHITECTURES "7.5+PTX")
+ set(CUDA_LIMIT_GPU_ARCHITECTURE "8.0")
endif()
endif()
if(CUDA_VERSION VERSION_GREATER_EQUAL "11.0")
list(APPEND CUDA_KNOWN_GPU_ARCHITECTURES "Ampere")
- list(APPEND CUDA_COMMON_GPU_ARCHITECTURES "8.0" "8.0+PTX")
+ list(APPEND CUDA_COMMON_GPU_ARCHITECTURES "8.0")
list(APPEND CUDA_ALL_GPU_ARCHITECTURES "8.0")
+ if(CUDA_VERSION VERSION_LESS "11.1")
+ list(APPEND CUDA_COMMON_GPU_ARCHITECTURES "8.0+PTX")
+ set(CUDA_LIMIT_GPU_ARCHITECTURE "8.6")
+ endif()
+endif()
+
+if(CUDA_VERSION VERSION_GREATER_EQUAL "11.1")
+ list(APPEND CUDA_COMMON_GPU_ARCHITECTURES "8.6" "8.6+PTX")
+ list(APPEND CUDA_ALL_GPU_ARCHITECTURES "8.6")
+
if(CUDA_VERSION VERSION_LESS "12.0")
set(CUDA_LIMIT_GPU_ARCHITECTURE "9.0")
endif()
diff --git a/Modules/FindJNI.cmake b/Modules/FindJNI.cmake
index eff815d..bbca952 100644
--- a/Modules/FindJNI.cmake
+++ b/Modules/FindJNI.cmake
@@ -60,7 +60,7 @@ macro(java_append_library_directories _var)
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^i.86$")
set(_java_libarch "i386")
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^aarch64")
- set(_java_libarch "arm64")
+ set(_java_libarch "arm64" "aarch64")
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^alpha")
set(_java_libarch "alpha")
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^arm")
diff --git a/Modules/FindPackageHandleStandardArgs.cmake b/Modules/FindPackageHandleStandardArgs.cmake
index 4d252bc..7af0171 100644
--- a/Modules/FindPackageHandleStandardArgs.cmake
+++ b/Modules/FindPackageHandleStandardArgs.cmake
@@ -294,16 +294,12 @@ function(FIND_PACKAGE_CHECK_VERSION version result)
unset (version_msg)
if (FPCV_HANDLE_VERSION_RANGE AND ${package}_FIND_VERSION_RANGE)
- if (${package}_FIND_VERSION_MIN VERSION_GREATER ${package}_FIND_VERSION_MAX
- OR (${package}_FIND_VERSION_MIN VERSION_EQUAL ${package}_FIND_VERSION_MAX
- AND ${package}_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE"))
- set (version_msg "Found unsuitable version \"${version}\", required range is empty (\"${${package}_FIND_VERSION_RANGE}\")")
- elseif ((${package}_FIND_VERSION_RANGE_MIN STREQUAL "INCLUDE"
- AND version VERSION_GREATER_EQUAL ${package}_FIND_VERSION_MIN)
+ if ((${package}_FIND_VERSION_RANGE_MIN STREQUAL "INCLUDE"
+ AND version VERSION_GREATER_EQUAL ${package}_FIND_VERSION_MIN)
AND ((${package}_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE"
AND version VERSION_LESS_EQUAL ${package}_FIND_VERSION_MAX)
OR (${package}_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE"
- AND version VERSION_LESS ${package}_FIND_VERSION_MAX)))
+ AND version VERSION_LESS ${package}_FIND_VERSION_MAX)))
set (version_ok TRUE)
set(version_msg "(found suitable version \"${version}\", required range is \"${${package}_FIND_VERSION_RANGE}\")")
else()
@@ -531,7 +527,7 @@ function(FIND_PACKAGE_HANDLE_STANDARD_ARGS _NAME _FIRST_ARG)
else()
set(FPCV_HANDLE_VERSION_RANGE NO_AUTHOR_WARNING_VERSION_RANGE)
endif()
- find_package_check_version (${_FOUND_VERSION} VERSION_OK RESULT_MESSAGE_VARIABLE VERSION_MSG
+ find_package_check_version ("${_FOUND_VERSION}" VERSION_OK RESULT_MESSAGE_VARIABLE VERSION_MSG
${FPCV_HANDLE_VERSION_RANGE})
else()
# if the package was not found, but a version was given, add that to the output:
diff --git a/Modules/FindPkgConfig.cmake b/Modules/FindPkgConfig.cmake
index 93827d8..2ad2c7e 100644
--- a/Modules/FindPkgConfig.cmake
+++ b/Modules/FindPkgConfig.cmake
@@ -31,7 +31,13 @@ set(PKG_CONFIG_VERSION 1)
if((NOT PKG_CONFIG_EXECUTABLE) AND (NOT "$ENV{PKG_CONFIG}" STREQUAL ""))
set(PKG_CONFIG_EXECUTABLE "$ENV{PKG_CONFIG}" CACHE FILEPATH "pkg-config executable")
endif()
-find_program(PKG_CONFIG_EXECUTABLE NAMES pkg-config DOC "pkg-config executable")
+
+set(PKG_CONFIG_NAMES "pkg-config")
+if(CMAKE_HOST_WIN32)
+ list(PREPEND PKG_CONFIG_NAMES "pkg-config.bat")
+endif()
+
+find_program(PKG_CONFIG_EXECUTABLE NAMES ${PKG_CONFIG_NAMES} DOC "pkg-config executable")
mark_as_advanced(PKG_CONFIG_EXECUTABLE)
set(_PKG_CONFIG_FAILURE_MESSAGE "")
@@ -47,7 +53,9 @@ if (PKG_CONFIG_EXECUTABLE)
string(APPEND _PKG_CONFIG_FAILURE_MESSAGE
"The command\n"
" \"${PKG_CONFIG_EXECUTABLE}\" --version\n"
- " failed with output\n${_PKG_CONFIG_VERSION_ERROR}"
+ " failed with output:\n${PKG_CONFIG_VERSION_STRING}\n"
+ " stderr: \n${_PKG_CONFIG_VERSION_ERROR}\n"
+ " result: \n${_PKG_CONFIG_VERSION_RESULT}"
)
set(PKG_CONFIG_EXECUTABLE "")
unset(PKG_CONFIG_VERSION_STRING)
diff --git a/Modules/FindPython.cmake b/Modules/FindPython.cmake
index 584f64d..2d13f48 100644
--- a/Modules/FindPython.cmake
+++ b/Modules/FindPython.cmake
@@ -10,6 +10,10 @@ FindPython
Find Python interpreter, compiler and development environment (include
directories and libraries).
+When a version is requested, it can be specified as a simple value or as a
+range. For a detailed description of version range usage and capabilities,
+refer to the :command:`find_package` command.
+
The following components are supported:
* ``Interpreter``: search for Python interpreter.
@@ -387,13 +391,39 @@ module suffix will include the ``Python_SOABI`` value, if any.
#]=======================================================================]
-set (_PYTHON_PREFIX Python)
+cmake_policy(PUSH)
+# numbers and boolean constants
+cmake_policy (SET CMP0012 NEW)
-if (DEFINED Python_FIND_VERSION)
+
+set (_PYTHON_PREFIX Python)
+unset (_Python_REQUIRED_VERSION_MAJOR)
+unset (_Python_REQUIRED_VERSIONS)
+
+if (Python_FIND_VERSION_RANGE)
+ # compute list of major versions
+ foreach (_Python_MAJOR IN ITEMS 3 2)
+ if (_Python_MAJOR VERSION_GREATER_EQUAL Python_FIND_VERSION_MIN_MAJOR
+ AND ((Python_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND _Python_MAJOR VERSION_LESS_EQUAL Python_FIND_VERSION_MAX)
+ OR (Python_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND _Python_MAJOR VERSION_LESS Python_FIND_VERSION_MAX)))
+ list (APPEND _Python_REQUIRED_VERSIONS ${_Python_MAJOR})
+ endif()
+ endforeach()
+ list (LENGTH _Python_REQUIRED_VERSIONS _Python_VERSION_COUNT)
+ if (_Python_VERSION_COUNT EQUAL 0)
+ unset (_Python_REQUIRED_VERSIONS)
+ elseif (_Python_VERSION_COUNT EQUAL 1)
+ set (_Python_REQUIRED_VERSION_MAJOR ${_Python_REQUIRED_VERSIONS})
+ endif()
+elseif (DEFINED Python_FIND_VERSION)
set (_Python_REQUIRED_VERSION_MAJOR ${Python_FIND_VERSION_MAJOR})
+else()
+ set (_Python_REQUIRED_VERSIONS 3 2)
+endif()
+if (_Python_REQUIRED_VERSION_MAJOR)
include (${CMAKE_CURRENT_LIST_DIR}/FindPython/Support.cmake)
-else()
+elseif (_Python_REQUIRED_VERSIONS)
# iterate over versions in quiet and NOT required modes to avoid multiple
# "Found" messages and prematurally failure.
set (_Python_QUIETLY ${Python_FIND_QUIETLY})
@@ -401,7 +431,6 @@ else()
set (Python_FIND_QUIETLY TRUE)
set (Python_FIND_REQUIRED FALSE)
- set (_Python_REQUIRED_VERSIONS 3 2)
set (_Python_REQUIRED_VERSION_LAST 2)
unset (_Python_INPUT_VARS)
@@ -435,10 +464,21 @@ else()
set (Python_FIND_REQUIRED ${_Python_REQUIRED})
if (Python_FIND_REQUIRED OR NOT Python_FIND_QUIETLY)
# call again validation command to get "Found" or error message
- find_package_handle_standard_args (Python HANDLE_COMPONENTS
+ find_package_handle_standard_args (Python HANDLE_COMPONENTS HANDLE_VERSION_RANGE
REQUIRED_VARS ${_Python_REQUIRED_VARS}
VERSION_VAR Python_VERSION)
endif()
+else()
+ # supported versions not in the specified range. Call final check
+ if (NOT Python_FIND_COMPONENTS)
+ set (Python_FIND_COMPONENTS Interpreter)
+ set (Python_FIND_REQUIRED_Interpreter TRUE)
+ endif()
+
+ include (${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+ find_package_handle_standard_args (Python HANDLE_COMPONENTS HANDLE_VERSION_RANGE
+ VERSION_VAR Python_VERSION
+ REASON_FAILURE_MESSAGE "Version range specified \"${Python_FIND_VERSION_RANGE}\" does not include supported versions")
endif()
if (COMMAND __Python_add_library)
@@ -448,3 +488,5 @@ if (COMMAND __Python_add_library)
endif()
unset (_PYTHON_PREFIX)
+
+cmake_policy(POP)
diff --git a/Modules/FindPython/Support.cmake b/Modules/FindPython/Support.cmake
index c8225c4..41b55ee 100644
--- a/Modules/FindPython/Support.cmake
+++ b/Modules/FindPython/Support.cmake
@@ -31,6 +31,7 @@ endif()
get_property(_${_PYTHON_PREFIX}_CMAKE_ROLE GLOBAL PROPERTY CMAKE_ROLE)
+include (${CMAKE_CURRENT_LIST_DIR}/../FindPackageHandleStandardArgs.cmake)
#
# helper commands
@@ -674,12 +675,7 @@ function (_PYTHON_VALIDATE_INTERPRETER)
return()
endif()
- cmake_parse_arguments (PARSE_ARGV 0 _PVI "EXACT;CHECK_EXISTS" "" "")
- if (_PVI_UNPARSED_ARGUMENTS)
- set (expected_version "${_PVI_UNPARSED_ARGUMENTS}")
- else()
- unset (expected_version)
- endif()
+ cmake_parse_arguments (PARSE_ARGV 0 _PVI "IN_RANGE;EXACT;CHECK_EXISTS" "VERSION" "")
if (_PVI_CHECK_EXISTS AND NOT EXISTS "${_${_PYTHON_PREFIX}_EXECUTABLE}")
# interpreter does not exist anymore
@@ -710,50 +706,69 @@ function (_PYTHON_VALIDATE_INTERPRETER)
endif()
endif()
- get_filename_component (python_name "${_${_PYTHON_PREFIX}_EXECUTABLE}" NAME)
+ if (_PVI_IN_RANGE OR _PVI_VERSION)
+ # retrieve full version
+ execute_process (COMMAND ${launcher} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
+ "import sys; sys.stdout.write('.'.join([str(x) for x in sys.version_info[:3]]))"
+ RESULT_VARIABLE result
+ OUTPUT_VARIABLE version
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if (result)
+ # interpreter is not usable
+ set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Cannot use the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"" PARENT_SCOPE)
+ set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND")
+ return()
+ endif()
- if (expected_version)
- if (NOT python_name STREQUAL "python${expected_version}${abi}${CMAKE_EXECUTABLE_SUFFIX}")
- # compute number of components for version
- string (REGEX REPLACE "[^.]" "" dots "${expected_version}")
- # add one dot because there is one dot less than there are components
+ if (_PVI_VERSION)
+ # check against specified version
+ ## compute number of components for version
+ string (REGEX REPLACE "[^.]" "" dots "${_PVI_VERSION}")
+ ## add one dot because there is one dot less than there are components
string (LENGTH "${dots}." count)
if (count GREATER 3)
set (count 3)
endif()
+ set (version_regex "^[0-9]+")
+ if (count EQUAL 3)
+ string (APPEND version_regex "\\.[0-9]+\\.[0-9]+")
+ elseif (count EQUAL 2)
+ string (APPEND version_regex "\\.[0-9]+")
+ endif()
+ # extract needed range
+ string (REGEX MATCH "${version_regex}" version "${version}")
- # executable found must have a specific version
- execute_process (COMMAND ${launcher} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
- "import sys; sys.stdout.write('.'.join([str(x) for x in sys.version_info[:${count}]]))"
- RESULT_VARIABLE result
- OUTPUT_VARIABLE version
- ERROR_QUIET
- OUTPUT_STRIP_TRAILING_WHITESPACE)
- if (result)
- # interpreter is not usable
- set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Cannot use the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"" PARENT_SCOPE)
+ if (_PVI_EXACT AND NOT version VERSION_EQUAL _PVI_VERSION)
+ # interpreter has wrong version
+ set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Wrong version for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"" PARENT_SCOPE)
set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND")
+ return()
else()
- if (_PVI_EXACT AND NOT version VERSION_EQUAL expected_version)
- # interpreter has wrong version
+ # check that version is OK
+ string(REGEX REPLACE "^([0-9]+)\\.?.*$" "\\1" major_version "${version}")
+ string(REGEX REPLACE "^([0-9]+)\\.?.*$" "\\1" expected_major_version "${_PVI_VERSION}")
+ if (NOT major_version VERSION_EQUAL expected_major_version
+ OR NOT version VERSION_GREATER_EQUAL _PVI_VERSION)
set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Wrong version for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"" PARENT_SCOPE)
set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND")
- else()
- # check that version is OK
- string(REGEX REPLACE "^([0-9]+)\\.?.*$" "\\1" major_version "${version}")
- string(REGEX REPLACE "^([0-9]+)\\.?.*$" "\\1" expected_major_version "${expected_version}")
- if (NOT major_version VERSION_EQUAL expected_major_version
- OR NOT version VERSION_GREATER_EQUAL expected_version)
- set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Wrong version for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"" PARENT_SCOPE)
- set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND")
- endif()
+ return()
endif()
endif()
- if (NOT _${_PYTHON_PREFIX}_EXECUTABLE)
+ endif()
+
+ if (_PVI_IN_RANGE)
+ # check if version is in the requested range
+ find_package_check_version ("${version}" in_range HANDLE_VERSION_RANGE)
+ if (NOT in_range)
+ # interpreter has invalid version
+ set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Wrong version for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"" PARENT_SCOPE)
+ set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND")
return()
endif()
endif()
else()
+ get_filename_component (python_name "${_${_PYTHON_PREFIX}_EXECUTABLE}" NAME)
if (NOT python_name STREQUAL "python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}${CMAKE_EXECUTABLE_SUFFIX}")
# executable found do not have version in name
# ensure major version is OK
@@ -805,15 +820,7 @@ function (_PYTHON_VALIDATE_COMPILER)
return()
endif()
- cmake_parse_arguments (PARSE_ARGV 0 _PVC "EXACT;CHECK_EXISTS" "" "")
- if (_PVC_UNPARSED_ARGUMENTS)
- set (major_version FALSE)
- set (expected_version "${_PVC_UNPARSED_ARGUMENTS}")
- else()
- set (major_version TRUE)
- set (expected_version "${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}")
- set (_PVC_EXACT TRUE)
- endif()
+ cmake_parse_arguments (PARSE_ARGV 0 _PVC "IN_RANGE;EXACT;CHECK_EXISTS" "VERSION" "")
if (_PVC_CHECK_EXISTS AND NOT EXISTS "${_${_PYTHON_PREFIX}_COMPILER}")
# Compiler does not exist anymore
@@ -826,19 +833,7 @@ function (_PYTHON_VALIDATE_COMPILER)
# retrieve python environment version from compiler
set (working_dir "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/PythonCompilerVersion.dir")
- if (major_version)
- # check only major version
- file (WRITE "${working_dir}/version.py" "import sys; sys.stdout.write(str(sys.version_info[0]))")
- else()
- # compute number of components for version
- string (REGEX REPLACE "[^.]" "" dots "${expected_version}")
- # add one dot because there is one dot less than there are components
- string (LENGTH "${dots}." count)
- if (count GREATER 3)
- set (count 3)
- endif()
- file (WRITE "${working_dir}/version.py" "import sys; sys.stdout.write('.'.join([str(x) for x in sys.version_info[:${count}]]))\n")
- endif()
+ file (WRITE "${working_dir}/version.py" "import sys; sys.stdout.write('.'.join([str(x) for x in sys.version_info[:3]]))\n")
execute_process (COMMAND ${launcher} "${_${_PYTHON_PREFIX}_COMPILER}"
${_${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_ARCH_FLAGS}
/target:exe /embed "${working_dir}/version.py"
@@ -858,11 +853,64 @@ function (_PYTHON_VALIDATE_COMPILER)
# compiler is not usable
set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE "Cannot use the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"" PARENT_SCOPE)
set_property (CACHE _${_PYTHON_PREFIX}_COMPILER PROPERTY VALUE "${_PYTHON_PREFIX}_COMPILER-NOTFOUND")
- elseif ((_PVC_EXACT AND NOT version VERSION_EQUAL expected_version)
- OR NOT version VERSION_GREATER_EQUAL expected_version)
- # Compiler has wrong version
- set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE "Wrong version for the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"" PARENT_SCOPE)
- set_property (CACHE _${_PYTHON_PREFIX}_COMPILER PROPERTY VALUE "${_PYTHON_PREFIX}_COMPILER-NOTFOUND")
+ return()
+ endif()
+
+ if (_PVC_VERSION OR _PVC_IN_RANGE)
+ if (_PVC_VERSION)
+ # check against specified version
+ ## compute number of components for version
+ string (REGEX REPLACE "[^.]" "" dots "${_PVC_VERSION}")
+ ## add one dot because there is one dot less than there are components
+ string (LENGTH "${dots}." count)
+ if (count GREATER 3)
+ set (count 3)
+ endif()
+ set (version_regex "^[0-9]+")
+ if (count EQUAL 3)
+ string (APPEND version_regex "\\.[0-9]+\\.[0-9]+")
+ elseif (count EQUAL 2)
+ string (APPEND version_regex "\\.[0-9]+")
+ endif()
+ # extract needed range
+ string (REGEX MATCH "${version_regex}" version "${version}")
+
+ if (_PVC_EXACT AND NOT version VERSION_EQUAL _PVC_VERSION)
+ # interpreter has wrong version
+ set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE "Wrong version for the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"" PARENT_SCOPE)
+ set_property (CACHE _${_PYTHON_PREFIX}_COMPILER PROPERTY VALUE "${_PYTHON_PREFIX}_COMPILER-NOTFOUND")
+ return()
+ else()
+ # check that version is OK
+ string(REGEX REPLACE "^([0-9]+)\\.?.*$" "\\1" major_version "${version}")
+ string(REGEX REPLACE "^([0-9]+)\\.?.*$" "\\1" expected_major_version "${_PVC_VERSION}")
+ if (NOT major_version VERSION_EQUAL expected_major_version
+ OR NOT version VERSION_GREATER_EQUAL _PVC_VERSION)
+ set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE "Wrong version for the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"" PARENT_SCOPE)
+ set_property (CACHE _${_PYTHON_PREFIX}_COMPILER PROPERTY VALUE "${_PYTHON_PREFIX}_COMPILER-NOTFOUND")
+ return()
+ endif()
+ endif()
+ endif()
+
+ if (_PVC_IN_RANGE)
+ # check if version is in the requested range
+ find_package_check_version ("${version}" in_range HANDLE_VERSION_RANGE)
+ if (NOT in_range)
+ # interpreter has invalid version
+ set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE "Wrong version for the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"" PARENT_SCOPE)
+ set_property (CACHE _${_PYTHON_PREFIX}_COMPILER PROPERTY VALUE "${_PYTHON_PREFIX}_COMPILER-NOTFOUND")
+ return()
+ endif()
+ endif()
+ else()
+ string(REGEX REPLACE "^([0-9]+)\\.?.*$" "\\1" major_version "${version}")
+ if (NOT major_version EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)
+ # Compiler has wrong major version
+ set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE "Wrong major version for the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"" PARENT_SCOPE)
+ set_property (CACHE _${_PYTHON_PREFIX}_COMPILER PROPERTY VALUE "${_PYTHON_PREFIX}_COMPILER-NOTFOUND")
+ return()
+ endif()
endif()
endfunction()
@@ -873,12 +921,7 @@ function (_PYTHON_VALIDATE_LIBRARY)
return()
endif()
- cmake_parse_arguments (PARSE_ARGV 0 _PVL "EXACT;CHECK_EXISTS" "" "")
- if (_PVL_UNPARSED_ARGUMENTS)
- set (expected_version ${_PVL_UNPARSED_ARGUMENTS})
- else()
- unset (expected_version)
- endif()
+ cmake_parse_arguments (PARSE_ARGV 0 _PVL "IN_RANGE;EXACT;CHECK_EXISTS" "VERSION" "")
if (_PVL_CHECK_EXISTS AND NOT EXISTS "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}")
# library does not exist anymore
@@ -899,13 +942,25 @@ function (_PYTHON_VALIDATE_LIBRARY)
set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong ABI for the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"" PARENT_SCOPE)
set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND")
else()
- if (expected_version)
- # library have only major.minor information
- string (REGEX MATCH "[0-9](\\.[0-9]+)?" version "${expected_version}")
- if ((_PVL_EXACT AND NOT lib_VERSION VERSION_EQUAL version) OR (lib_VERSION VERSION_LESS version))
- # library has wrong version
- set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong version for the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"" PARENT_SCOPE)
- set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND")
+ if (_PVL_VERSION OR _PVL_IN_RANGE)
+ if (_PVL_VERSION)
+ # library have only major.minor information
+ string (REGEX MATCH "[0-9](\\.[0-9]+)?" version "${_PVL_VERSION}")
+ if ((_PVL_EXACT AND NOT lib_VERSION VERSION_EQUAL version) OR (lib_VERSION VERSION_LESS version))
+ # library has wrong version
+ set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong version for the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"" PARENT_SCOPE)
+ set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND")
+ endif()
+ endif()
+
+ if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE AND _PVL_IN_RANGE)
+ # check if library version is in the requested range
+ find_package_check_version ("${lib_VERSION}" in_range HANDLE_VERSION_RANGE)
+ if (NOT in_range)
+ # library has wrong version
+ set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong version for the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"" PARENT_SCOPE)
+ set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND")
+ endif()
endif()
else()
if (NOT lib_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)
@@ -932,12 +987,7 @@ function (_PYTHON_VALIDATE_INCLUDE_DIR)
return()
endif()
- cmake_parse_arguments (PARSE_ARGV 0 _PVID "EXACT;CHECK_EXISTS" "" "")
- if (_PVID_UNPARSED_ARGUMENTS)
- set (expected_version ${_PVID_UNPARSED_ARGUMENTS})
- else()
- unset (expected_version)
- endif()
+ cmake_parse_arguments (PARSE_ARGV 0 _PVID "IN_RANGE;EXACT;CHECK_EXISTS" "VERSION" "")
if (_PVID_CHECK_EXISTS AND NOT EXISTS "${_${_PYTHON_PREFIX}_INCLUDE_DIR}")
# include file does not exist anymore
@@ -954,11 +1004,23 @@ function (_PYTHON_VALIDATE_INCLUDE_DIR)
set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong ABI for the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"" PARENT_SCOPE)
set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND")
else()
- if (expected_version)
- if ((_PVID_EXACT AND NOT inc_VERSION VERSION_EQUAL expected_version) OR (inc_VERSION VERSION_LESS expected_version))
- # include dir has wrong version
- set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong version for the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"" PARENT_SCOPE)
- set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND")
+ if (_PVID_VERSION OR _PVID_IN_RANGE)
+ if (_PVID_VERSION)
+ if ((_PVID_EXACT AND NOT inc_VERSION VERSION_EQUAL expected_version) OR (inc_VERSION VERSION_LESS expected_version))
+ # include dir has wrong version
+ set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong version for the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"" PARENT_SCOPE)
+ set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND")
+ endif()
+ endif()
+
+ if (_${_PYTHON_PREFIX}_INCLUDE_DIR AND PVID_IN_RANGE)
+ # check if include dir is in the request range
+ find_package_check_version ("${inc_VERSION}" in_range HANDLE_VERSION_RANGE)
+ if (NOT in_range)
+ # include dir has wrong version
+ set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong version for the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"" PARENT_SCOPE)
+ set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND")
+ endif()
endif()
else()
if (NOT inc_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)
@@ -1020,13 +1082,27 @@ function (_PYTHON_SET_DEVELOPMENT_MODULE_FOUND module)
endfunction()
-# If major version is specified, it must be the same as internal major version
-if (DEFINED ${_PYTHON_PREFIX}_FIND_VERSION_MAJOR
- AND NOT ${_PYTHON_PREFIX}_FIND_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)
- _python_display_failure ("Could NOT find ${_PYTHON_PREFIX}: Wrong major version specified is \"${${_PYTHON_PREFIX}_FIND_VERSION_MAJOR}\", but expected major version is \"${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}\"")
+if (${_PYTHON_PREFIX}_FIND_VERSION_RANGE)
+ # range must include internal major version
+ if (${_PYTHON_PREFIX}_FIND_VERSION_MIN_MAJOR VERSION_GREATER _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR
+ OR ((${_PYTHON_PREFIX}_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE"
+ AND ${_PYTHON_PREFIX}_FIND_VERSION_MAX VERSION_LESS _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)
+ OR (${_PYTHON_PREFIX}_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE"
+ AND ${_PYTHON_PREFIX}_FIND_VERSION_MAX VERSION_LESS_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)))
+ _python_display_failure ("Could NOT find ${_PYTHON_PREFIX}: Wrong version range specified is \"${${_PYTHON_PREFIX}_FIND_VERSION_RANGE}\", but expected version range must include major version \"${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}\"")
- cmake_policy(POP)
- return()
+ cmake_policy(POP)
+ return()
+ endif()
+else()
+ if (DEFINED ${_PYTHON_PREFIX}_FIND_VERSION_MAJOR
+ AND NOT ${_PYTHON_PREFIX}_FIND_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)
+ # If major version is specified, it must be the same as internal major version
+ _python_display_failure ("Could NOT find ${_PYTHON_PREFIX}: Wrong major version specified is \"${${_PYTHON_PREFIX}_FIND_VERSION_MAJOR}\", but expected major version is \"${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}\"")
+
+ cmake_policy(POP)
+ return()
+ endif()
endif()
@@ -1070,18 +1146,32 @@ list (REMOVE_DUPLICATES _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS)
set (_${_PYTHON_PREFIX}_FIND_VERSIONS ${_${_PYTHON_PREFIX}_VERSIONS})
unset (_${_PYTHON_PREFIX}_FIND_VERSION_EXACT)
-if (${_PYTHON_PREFIX}_FIND_VERSION_COUNT)
- if (${_PYTHON_PREFIX}_FIND_VERSION_EXACT)
- set (_${_PYTHON_PREFIX}_FIND_VERSION_EXACT "EXACT")
- set (_${_PYTHON_PREFIX}_FIND_VERSIONS ${${_PYTHON_PREFIX}_FIND_VERSION_MAJOR}.${${_PYTHON_PREFIX}_FIND_VERSION_MINOR})
- else()
- unset (_${_PYTHON_PREFIX}_FIND_VERSIONS)
- # add all compatible versions
- foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_VERSIONS)
- if (_${_PYTHON_PREFIX}_VERSION VERSION_GREATER_EQUAL "${${_PYTHON_PREFIX}_FIND_VERSION_MAJOR}.${${_PYTHON_PREFIX}_FIND_VERSION_MINOR}")
- list (APPEND _${_PYTHON_PREFIX}_FIND_VERSIONS ${_${_PYTHON_PREFIX}_VERSION})
- endif()
- endforeach()
+if (${_PYTHON_PREFIX}_FIND_VERSION_RANGE)
+ unset (_${_PYTHON_PREFIX}_FIND_VERSIONS)
+ foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_VERSIONS)
+ if ((${_PYTHON_PREFIX}_FIND_VERSION_RANGE_MIN STREQUAL "INCLUDE"
+ AND _${_PYTHON_PREFIX}_VERSION VERSION_GREATER_EQUAL ${_PYTHON_PREFIX}_FIND_VERSION_MIN)
+ AND ((${_PYTHON_PREFIX}_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE"
+ AND _${_PYTHON_PREFIX}_VERSION VERSION_LESS_EQUAL ${_PYTHON_PREFIX}_FIND_VERSION_MAX)
+ OR (${_PYTHON_PREFIX}_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE"
+ AND _${_PYTHON_PREFIX}_VERSION VERSION_LESS ${_PYTHON_PREFIX}_FIND_VERSION_MAX)))
+ list (APPEND _${_PYTHON_PREFIX}_FIND_VERSIONS ${_${_PYTHON_PREFIX}_VERSION})
+ endif()
+ endforeach()
+else()
+ if (${_PYTHON_PREFIX}_FIND_VERSION_COUNT GREATER 1)
+ if (${_PYTHON_PREFIX}_FIND_VERSION_EXACT)
+ set (_${_PYTHON_PREFIX}_FIND_VERSION_EXACT "EXACT")
+ set (_${_PYTHON_PREFIX}_FIND_VERSIONS ${${_PYTHON_PREFIX}_FIND_VERSION_MAJOR}.${${_PYTHON_PREFIX}_FIND_VERSION_MINOR})
+ else()
+ unset (_${_PYTHON_PREFIX}_FIND_VERSIONS)
+ # add all compatible versions
+ foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_VERSIONS)
+ if (_${_PYTHON_PREFIX}_VERSION VERSION_GREATER_EQUAL "${${_PYTHON_PREFIX}_FIND_VERSION_MAJOR}.${${_PYTHON_PREFIX}_FIND_VERSION_MINOR}")
+ list (APPEND _${_PYTHON_PREFIX}_FIND_VERSIONS ${_${_PYTHON_PREFIX}_VERSION})
+ endif()
+ endforeach()
+ endif()
endif()
endif()
@@ -1300,14 +1390,26 @@ function (_PYTHON_CHECK_DEVELOPMENT_SIGNATURE module)
string (MD5 signature "${signature}")
if (signature STREQUAL _${_PYTHON_PREFIX}_DEVELOPMENT_${id}_SIGNATURE)
if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS)
- _python_validate_library (${${_PYTHON_PREFIX}_FIND_VERSION}
- ${_${_PYTHON_PREFIX}_FIND_VERSION_EXACT}
- CHECK_EXISTS)
+ if (${_PYTHON_PREFIX}_FIND_VERSION_EXACT)
+ _python_validate_library (VERSION ${${_PYTHON_PREFIX}_FIND_VERSION} EXACT CHECK_EXISTS)
+ elseif (${_PYTHON_PREFIX}_FIND_VERSION_RANGE)
+ _python_validate_library (IN_RANGE CHECK_EXISTS)
+ elseif (DEFINED ${_PYTHON_PREFIX}_FIND_VERSION)
+ _python_validate_library (VERSION ${${_PYTHON_PREFIX}_FIND_VERSION} CHECK_EXISTS)
+ else()
+ _python_validate_library (CHECK_EXISTS)
+ endif()
endif()
if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS)
- _python_validate_include_dir (${${_PYTHON_PREFIX}_FIND_VERSION}
- ${_${_PYTHON_PREFIX}_FIND_VERSION_EXACT}
- CHECK_EXISTS)
+ if (${_PYTHON_PREFIX}_FIND_VERSION_EXACT)
+ _python_validate_include_dir (VERSION ${${_PYTHON_PREFIX}_FIND_VERSION} EXACT CHECK_EXISTS)
+ elseif (${_PYTHON_PREFIX}_FIND_VERSION_RANGE)
+ _python_validate_include_dir (IN_RANGE CHECK_EXISTS)
+ elseif (${_PYTHON_PREFIX}_FIND_VERSION)
+ _python_validate_include_dir (VERSION ${${_PYTHON_PREFIX}_FIND_VERSION} CHECK_EXISTS)
+ else()
+ _python_validate_include_dir (CHECK_EXISTS)
+ endif()
endif()
else()
if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS)
@@ -1384,9 +1486,13 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
if (__${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE STREQUAL _${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE)
# check version validity
if (${_PYTHON_PREFIX}_FIND_VERSION_EXACT)
- _python_validate_interpreter (${${_PYTHON_PREFIX}_FIND_VERSION} EXACT CHECK_EXISTS)
+ _python_validate_interpreter (VERSION ${${_PYTHON_PREFIX}_FIND_VERSION} EXACT CHECK_EXISTS)
+ elseif (${_PYTHON_PREFIX}_FIND_VERSION_RANGE)
+ _python_validate_interpreter (IN_RANGE CHECK_EXISTS)
+ elseif (DEFINED ${_PYTHON_PREFIX}_FIND_VERSION)
+ _python_validate_interpreter (VERSION ${${_PYTHON_PREFIX}_FIND_VERSION} CHECK_EXISTS)
else()
- _python_validate_interpreter (${${_PYTHON_PREFIX}_FIND_VERSION} CHECK_EXISTS)
+ _python_validate_interpreter (CHECK_EXISTS)
endif()
else()
unset (_${_PYTHON_PREFIX}_EXECUTABLE CACHE)
@@ -1410,6 +1516,13 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
# Registry Paths
_python_get_registries (_${_PYTHON_PREFIX}_REGISTRY_PATHS VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS})
+ set (_${_PYTHON_PREFIX}_VALIDATE_OPTIONS ${_${_PYTHON_PREFIX}_FIND_VERSION_EXACT})
+ if (${_PYTHON_PREFIX}_FIND_VERSION_RANGE)
+ list (APPEND _${_PYTHON_PREFIX}_VALIDATE_OPTIONS IN_RANGE)
+ elseif (DEFINED ${_PYTHON_PREFIX}_FIND_VERSION)
+ list (APPEND VERSION ${${_PYTHON_PREFIX}_FIND_VERSION})
+ endif()
+
while (TRUE)
# Virtual environments handling
if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY)$")
@@ -1424,7 +1537,7 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
NO_SYSTEM_ENVIRONMENT_PATH
NO_CMAKE_SYSTEM_PATH)
- _python_validate_interpreter (${${_PYTHON_PREFIX}_FIND_VERSION} ${_${_PYTHON_PREFIX}_FIND_VERSION_EXACT})
+ _python_validate_interpreter (${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
if (_${_PYTHON_PREFIX}_EXECUTABLE)
break()
endif()
@@ -1445,7 +1558,7 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
NO_CMAKE_ENVIRONMENT_PATH
NO_SYSTEM_ENVIRONMENT_PATH
NO_CMAKE_SYSTEM_PATH)
- _python_validate_interpreter (${${_PYTHON_PREFIX}_FIND_VERSION} ${_${_PYTHON_PREFIX}_FIND_VERSION_EXACT})
+ _python_validate_interpreter (${${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
if (_${_PYTHON_PREFIX}_EXECUTABLE)
break()
endif()
@@ -1460,7 +1573,7 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
NO_SYSTEM_ENVIRONMENT_PATH
NO_CMAKE_SYSTEM_PATH)
- _python_validate_interpreter (${${_PYTHON_PREFIX}_FIND_VERSION} ${_${_PYTHON_PREFIX}_FIND_VERSION_EXACT})
+ _python_validate_interpreter (${${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
if (_${_PYTHON_PREFIX}_EXECUTABLE)
break()
endif()
@@ -1474,7 +1587,7 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
NO_SYSTEM_ENVIRONMENT_PATH
NO_CMAKE_SYSTEM_PATH)
- _python_validate_interpreter (${${_PYTHON_PREFIX}_FIND_VERSION} ${_${_PYTHON_PREFIX}_FIND_VERSION_EXACT})
+ _python_validate_interpreter (${${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
if (_${_PYTHON_PREFIX}_EXECUTABLE)
break()
endif()
@@ -1483,7 +1596,7 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
NAMES ${_${_PYTHON_PREFIX}_NAMES}
NAMES_PER_DIR
PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES})
- _python_validate_interpreter (${${_PYTHON_PREFIX}_FIND_VERSION} ${_${_PYTHON_PREFIX}_FIND_VERSION_EXACT})
+ _python_validate_interpreter (${${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
if (_${_PYTHON_PREFIX}_EXECUTABLE)
break()
endif()
@@ -1496,7 +1609,7 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
NO_DEFAULT_PATH)
- _python_validate_interpreter (${${_PYTHON_PREFIX}_FIND_VERSION} ${_${_PYTHON_PREFIX}_FIND_VERSION_EXACT})
+ _python_validate_interpreter (${${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
if (_${_PYTHON_PREFIX}_EXECUTABLE)
break()
endif()
@@ -1509,7 +1622,7 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
NO_DEFAULT_PATH)
- _python_validate_interpreter (${${_PYTHON_PREFIX}_FIND_VERSION} ${_${_PYTHON_PREFIX}_FIND_VERSION_EXACT})
+ _python_validate_interpreter (${${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
if (_${_PYTHON_PREFIX}_EXECUTABLE)
break()
endif()
@@ -1519,6 +1632,11 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
endwhile()
else()
# look-up for various versions and locations
+ set (_${_PYTHON_PREFIX}_VALIDATE_OPTIONS EXACT)
+ if (${_PYTHON_PREFIX}_FIND_VERSION_RANGE)
+ list (APPEND _${_PYTHON_PREFIX}_VALIDATE_OPTIONS IN_RANGE)
+ endif()
+
foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS)
_python_get_names (_${_PYTHON_PREFIX}_NAMES VERSION ${_${_PYTHON_PREFIX}_VERSION} POSIX INTERPRETER)
_python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES VERSION ${_${_PYTHON_PREFIX}_VERSION} INTERPRETER)
@@ -1538,7 +1656,7 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
NO_CMAKE_ENVIRONMENT_PATH
NO_SYSTEM_ENVIRONMENT_PATH
NO_CMAKE_SYSTEM_PATH)
- _python_validate_interpreter (${_${_PYTHON_PREFIX}_VERSION} EXACT)
+ _python_validate_interpreter (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
if (_${_PYTHON_PREFIX}_EXECUTABLE)
break()
endif()
@@ -1573,7 +1691,7 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
NO_CMAKE_SYSTEM_PATH)
endif()
- _python_validate_interpreter (${_${_PYTHON_PREFIX}_VERSION} EXACT)
+ _python_validate_interpreter (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
if (_${_PYTHON_PREFIX}_EXECUTABLE)
break()
endif()
@@ -1586,7 +1704,7 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
NO_SYSTEM_ENVIRONMENT_PATH
NO_CMAKE_SYSTEM_PATH)
- _python_validate_interpreter (${_${_PYTHON_PREFIX}_VERSION} EXACT)
+ _python_validate_interpreter (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
if (_${_PYTHON_PREFIX}_EXECUTABLE)
break()
endif()
@@ -1599,7 +1717,7 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
find_program (_${_PYTHON_PREFIX}_EXECUTABLE
NAMES ${_${_PYTHON_PREFIX}_NAMES}
PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES})
- _python_validate_interpreter (${_${_PYTHON_PREFIX}_VERSION} EXACT)
+ _python_validate_interpreter (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
if (_${_PYTHON_PREFIX}_EXECUTABLE)
break()
endif()
@@ -1624,7 +1742,7 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
NO_DEFAULT_PATH)
endif()
- _python_validate_interpreter (${_${_PYTHON_PREFIX}_VERSION} EXACT)
+ _python_validate_interpreter (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
if (_${_PYTHON_PREFIX}_EXECUTABLE)
break()
endif()
@@ -1825,9 +1943,13 @@ if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
if (__${_PYTHON_PREFIX}_COMPILER_SIGNATURE STREQUAL _${_PYTHON_PREFIX}_COMPILER_SIGNATURE)
# check version validity
if (${_PYTHON_PREFIX}_FIND_VERSION_EXACT)
- _python_validate_compiler (${${_PYTHON_PREFIX}_FIND_VERSION} EXACT CHECK_EXISTS)
+ _python_validate_compiler (VERSION ${${_PYTHON_PREFIX}_FIND_VERSION} EXACT CHECK_EXISTS)
+ elseif (${_PYTHON_PREFIX}_FIND_VERSION_RANGE)
+ _python_validate_compiler (IN_RANGE CHECK_EXISTS)
+ elseif (DEFINED ${_PYTHON_PREFIX}_FIND_VERSION)
+ _python_validate_compiler (VERSION ${${_PYTHON_PREFIX}_FIND_VERSION} CHECK_EXISTS)
else()
- _python_validate_compiler (${${_PYTHON_PREFIX}_FIND_VERSION} CHECK_EXISTS)
+ _python_validate_compiler (CHECK_EXISTS)
endif()
else()
unset (_${_PYTHON_PREFIX}_COMPILER CACHE)
@@ -1862,6 +1984,13 @@ if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
IMPLEMENTATIONS IronPython
VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS})
+ set (_${_PYTHON_PREFIX}_VALIDATE_OPTIONS ${_${_PYTHON_PREFIX}_FIND_VERSION_EXACT})
+ if (${_PYTHON_PREFIX}_FIND_VERSION_RANGE)
+ list (APPEND _${_PYTHON_PREFIX}_VALIDATE_OPTIONS IN_RANGE)
+ elseif (DEFINED ${_PYTHON_PREFIX}_FIND_VERSION)
+ list (APPEND VERSION ${${_PYTHON_PREFIX}_FIND_VERSION})
+ endif()
+
while (TRUE)
# Apple frameworks handling
if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST")
@@ -1875,7 +2004,7 @@ if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
NO_CMAKE_ENVIRONMENT_PATH
NO_SYSTEM_ENVIRONMENT_PATH
NO_CMAKE_SYSTEM_PATH)
- _python_validate_compiler (${${_PYTHON_PREFIX}_FIND_VERSION} ${_${_PYTHON_PREFIX}_FIND_VERSION_EXACT})
+ _python_validate_compiler (${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
if (_${_PYTHON_PREFIX}_COMPILER)
break()
endif()
@@ -1890,7 +2019,7 @@ if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
NO_SYSTEM_ENVIRONMENT_PATH
NO_CMAKE_SYSTEM_PATH)
- _python_validate_compiler (${${_PYTHON_PREFIX}_FIND_VERSION} ${_${_PYTHON_PREFIX}_FIND_VERSION_EXACT})
+ _python_validate_compiler (${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
if (_${_PYTHON_PREFIX}_COMPILER)
break()
endif()
@@ -1904,7 +2033,7 @@ if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
NO_SYSTEM_ENVIRONMENT_PATH
NO_CMAKE_SYSTEM_PATH)
- _python_validate_compiler (${${_PYTHON_PREFIX}_FIND_VERSION} ${_${_PYTHON_PREFIX}_FIND_VERSION_EXACT})
+ _python_validate_compiler (${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
if (_${_PYTHON_PREFIX}_COMPILER)
break()
endif()
@@ -1914,7 +2043,7 @@ if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES}
NAMES_PER_DIR
PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES})
- _python_validate_compiler (${${_PYTHON_PREFIX}_FIND_VERSION} ${_${_PYTHON_PREFIX}_FIND_VERSION_EXACT})
+ _python_validate_compiler (${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
if (_${_PYTHON_PREFIX}_COMPILER)
break()
endif()
@@ -1927,7 +2056,7 @@ if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
NO_DEFAULT_PATH)
- _python_validate_compiler (${${_PYTHON_PREFIX}_FIND_VERSION} ${_${_PYTHON_PREFIX}_FIND_VERSION_EXACT})
+ _python_validate_compiler (${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
if (_${_PYTHON_PREFIX}_COMPILER)
break()
endif()
@@ -1940,6 +2069,7 @@ if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
NO_DEFAULT_PATH)
+ _python_validate_compiler (${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
if (_${_PYTHON_PREFIX}_COMPILER)
break()
endif()
@@ -1949,6 +2079,11 @@ if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
endwhile()
else()
# try using root dir and registry
+ set (_${_PYTHON_PREFIX}_VALIDATE_OPTIONS EXACT)
+ if (${_PYTHON_PREFIX}_FIND_VERSION_RANGE)
+ list (APPEND _${_PYTHON_PREFIX}_VALIDATE_OPTIONS IN_RANGE)
+ endif()
+
foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS)
_python_get_names (_${_PYTHON_PREFIX}_COMPILER_NAMES
IMPLEMENTATIONS IronPython
@@ -1979,7 +2114,7 @@ if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
NO_CMAKE_ENVIRONMENT_PATH
NO_SYSTEM_ENVIRONMENT_PATH
NO_CMAKE_SYSTEM_PATH)
- _python_validate_compiler (${_${_PYTHON_PREFIX}_VERSION} EXACT)
+ _python_validate_compiler (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
if (_${_PYTHON_PREFIX}_COMPILER)
break()
endif()
@@ -1994,7 +2129,7 @@ if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
NO_SYSTEM_ENVIRONMENT_PATH
NO_CMAKE_SYSTEM_PATH)
- _python_validate_compiler (${_${_PYTHON_PREFIX}_VERSION} EXACT)
+ _python_validate_compiler (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
if (_${_PYTHON_PREFIX}_COMPILER)
break()
endif()
@@ -2008,7 +2143,7 @@ if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
NO_SYSTEM_ENVIRONMENT_PATH
NO_CMAKE_SYSTEM_PATH)
- _python_validate_compiler (${_${_PYTHON_PREFIX}_VERSION} EXACT)
+ _python_validate_compiler (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
if (_${_PYTHON_PREFIX}_COMPILER)
break()
endif()
@@ -2021,7 +2156,7 @@ if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
NO_DEFAULT_PATH)
- _python_validate_compiler (${_${_PYTHON_PREFIX}_VERSION} EXACT)
+ _python_validate_compiler (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
if (_${_PYTHON_PREFIX}_COMPILER)
break()
endif()
@@ -2034,7 +2169,7 @@ if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
NO_DEFAULT_PATH)
- _python_validate_compiler (${_${_PYTHON_PREFIX}_VERSION} EXACT)
+ _python_validate_compiler (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
if (_${_PYTHON_PREFIX}_COMPILER)
break()
endif()
@@ -2054,6 +2189,7 @@ if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES}
HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS}
PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES})
+ _python_validate_compiler ()
endif()
endif()
@@ -2754,7 +2890,6 @@ if (("Development.Module" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
if (_${_PYTHON_PREFIX}_INCLUDE_DIR)
# retrieve version from header file
_python_get_version (INCLUDE PREFIX _${_PYTHON_PREFIX}_INC_)
-
if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE)
if ("${_${_PYTHON_PREFIX}_INC_VERSION_MAJOR}.${_${_PYTHON_PREFIX}_INC_VERSION_MINOR}"
VERSION_EQUAL _${_PYTHON_PREFIX}_VERSION)
@@ -2980,10 +3115,10 @@ foreach (_${_PYTHON_PREFIX}_COMPONENT IN ITEMS Interpreter Compiler Development
endif()
endforeach()
-include (${CMAKE_CURRENT_LIST_DIR}/../FindPackageHandleStandardArgs.cmake)
find_package_handle_standard_args (${_PYTHON_PREFIX}
REQUIRED_VARS ${_${_PYTHON_PREFIX}_REQUIRED_VARS}
VERSION_VAR ${_PYTHON_PREFIX}_VERSION
+ HANDLE_VERSION_RANGE
HANDLE_COMPONENTS
REASON_FAILURE_MESSAGE "${_${_PYTHON_PREFIX}_REASON_FAILURE}")
diff --git a/Modules/FindPython2.cmake b/Modules/FindPython2.cmake
index 1c75011..97e376d 100644
--- a/Modules/FindPython2.cmake
+++ b/Modules/FindPython2.cmake
@@ -10,6 +10,10 @@ FindPython2
Find Python 2 interpreter, compiler and development environment (include
directories and libraries).
+When a version is requested, it can be specified as a simple value or as a
+range. For a detailed description of version range usage and capabilities,
+refer to the :command:`find_package` command.
+
The following components are supported:
* ``Interpreter``: search for Python 2 interpreter
diff --git a/Modules/FindPython3.cmake b/Modules/FindPython3.cmake
index e6e9f04..266b50a 100644
--- a/Modules/FindPython3.cmake
+++ b/Modules/FindPython3.cmake
@@ -10,6 +10,10 @@ FindPython3
Find Python 3 interpreter, compiler and development environment (include
directories and libraries).
+When a version is requested, it can be specified as a simple value or as a
+range. For a detailed description of version range usage and capabilities,
+refer to the :command:`find_package` command.
+
The following components are supported:
* ``Interpreter``: search for Python 3 interpreter
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 1be424a..d0d9459 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -946,6 +946,7 @@ set(CTEST_SRCS cmCTest.cxx
CTest/cmCTestResourceAllocator.cxx
CTest/cmCTestResourceSpec.cxx
CTest/cmCTestLaunch.cxx
+ CTest/cmCTestLaunchReporter.cxx
CTest/cmCTestMemCheckCommand.cxx
CTest/cmCTestMemCheckHandler.cxx
CTest/cmCTestMultiProcessHandler.cxx
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index 571d4b5..ce9646d 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 18)
-set(CMake_VERSION_PATCH 20200927)
+set(CMake_VERSION_PATCH 20201001)
#set(CMake_VERSION_RC 0)
set(CMake_VERSION_IS_DIRTY 0)
diff --git a/Source/CTest/cmCTestBuildHandler.cxx b/Source/CTest/cmCTestBuildHandler.cxx
index 9997548..bb700eba 100644
--- a/Source/CTest/cmCTestBuildHandler.cxx
+++ b/Source/CTest/cmCTestBuildHandler.cxx
@@ -14,6 +14,7 @@
#include "cmsys/Process.h"
#include "cmCTest.h"
+#include "cmCTestLaunchReporter.h"
#include "cmDuration.h"
#include "cmFileTimeCache.h"
#include "cmGeneratedFileStream.h"
@@ -887,15 +888,28 @@ int cmCTestBuildHandler::RunMakeCommand(const std::string& command,
if (*retVal) {
// If there was an error running command, report that on the
// dashboard.
- cmCTestBuildErrorWarning errorwarning;
- errorwarning.LogLine = 1;
- errorwarning.Text = cmStrCat(
- "*** WARNING non-zero return value in ctest from: ", argv[0]);
- errorwarning.PreContext.clear();
- errorwarning.PostContext.clear();
- errorwarning.Error = false;
- this->ErrorsAndWarnings.push_back(std::move(errorwarning));
- this->TotalWarnings++;
+ if (this->UseCTestLaunch) {
+ cmCTestLaunchReporter reporter;
+ reporter.RealArgs = args;
+ reporter.ComputeFileNames();
+ reporter.ExitCode = *retVal;
+ reporter.Process = cp;
+ // Use temporary BuildLog file to populate this error for CDash.
+ ofs.flush();
+ reporter.LogOut = this->LogFileNames["Build"];
+ reporter.LogOut += ".tmp";
+ reporter.WriteXML();
+ } else {
+ cmCTestBuildErrorWarning errorwarning;
+ errorwarning.LogLine = 1;
+ errorwarning.Text = cmStrCat(
+ "*** WARNING non-zero return value in ctest from: ", argv[0]);
+ errorwarning.PreContext.clear();
+ errorwarning.PostContext.clear();
+ errorwarning.Error = false;
+ this->ErrorsAndWarnings.push_back(std::move(errorwarning));
+ this->TotalWarnings++;
+ }
}
}
} else if (result == cmsysProcess_State_Exception) {
diff --git a/Source/CTest/cmCTestGenericHandler.cxx b/Source/CTest/cmCTestGenericHandler.cxx
index a71f550..91818bb 100644
--- a/Source/CTest/cmCTestGenericHandler.cxx
+++ b/Source/CTest/cmCTestGenericHandler.cxx
@@ -6,6 +6,7 @@
#include <utility>
#include "cmCTest.h"
+#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
cmCTestGenericHandler::cmCTestGenericHandler()
@@ -122,6 +123,8 @@ bool cmCTestGenericHandler::StartLogFile(const char* name,
ostr << "_" << this->CTest->GetCurrentTag();
}
ostr << ".log";
+ this->LogFileNames[name] =
+ cmStrCat(this->CTest->GetBinaryDir(), "/Testing/Temporary/", ostr.str());
if (!this->CTest->OpenOutputFile("Temporary", ostr.str(), xofs)) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
"Cannot create log file: " << ostr.str() << std::endl);
diff --git a/Source/CTest/cmCTestGenericHandler.h b/Source/CTest/cmCTestGenericHandler.h
index 591d9cd..89d7596 100644
--- a/Source/CTest/cmCTestGenericHandler.h
+++ b/Source/CTest/cmCTestGenericHandler.h
@@ -100,6 +100,7 @@ protected:
cmCTest* CTest;
t_StringToString Options;
t_StringToString PersistentOptions;
+ t_StringToString LogFileNames;
cmCTestCommand* Command;
int SubmitIndex;
diff --git a/Source/CTest/cmCTestLaunch.cxx b/Source/CTest/cmCTestLaunch.cxx
index 647f5ff..b9ed033 100644
--- a/Source/CTest/cmCTestLaunch.cxx
+++ b/Source/CTest/cmCTestLaunch.cxx
@@ -2,7 +2,6 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestLaunch.h"
-#include <cstdlib>
#include <cstring>
#include <iostream>
@@ -10,8 +9,7 @@
#include "cmsys/Process.h"
#include "cmsys/RegularExpression.hxx"
-#include "cmCryptoHash.h"
-#include "cmGeneratedFileStream.h"
+#include "cmCTestLaunchReporter.h"
#include "cmGlobalGenerator.h"
#include "cmMakefile.h"
#include "cmProcessOutput.h"
@@ -19,7 +17,6 @@
#include "cmStateSnapshot.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
-#include "cmXMLWriter.h"
#include "cmake.h"
#ifdef _WIN32
@@ -30,16 +27,14 @@
cmCTestLaunch::cmCTestLaunch(int argc, const char* const* argv)
{
- this->Passthru = true;
this->Process = nullptr;
- this->ExitCode = 1;
- this->CWD = cmSystemTools::GetCurrentWorkingDirectory();
if (!this->ParseArguments(argc, argv)) {
return;
}
- this->ComputeFileNames();
+ this->Reporter.RealArgs = this->RealArgs;
+ this->Reporter.ComputeFileNames();
this->ScrapeRulesLoaded = false;
this->HaveOut = false;
@@ -50,10 +45,6 @@ cmCTestLaunch::cmCTestLaunch(int argc, const char* const* argv)
cmCTestLaunch::~cmCTestLaunch()
{
cmsysProcess_Delete(this->Process);
- if (!this->Passthru) {
- cmSystemTools::RemoveFile(this->LogOut);
- cmSystemTools::RemoveFile(this->LogErr);
- }
}
bool cmCTestLaunch::ParseArguments(int argc, const char* const* argv)
@@ -93,28 +84,28 @@ bool cmCTestLaunch::ParseArguments(int argc, const char* const* argv)
} else if (strcmp(arg, "--filter-prefix") == 0) {
doing = DoingFilterPrefix;
} else if (doing == DoingOutput) {
- this->OptionOutput = arg;
+ this->Reporter.OptionOutput = arg;
doing = DoingNone;
} else if (doing == DoingSource) {
- this->OptionSource = arg;
+ this->Reporter.OptionSource = arg;
doing = DoingNone;
} else if (doing == DoingLanguage) {
- this->OptionLanguage = arg;
- if (this->OptionLanguage == "CXX") {
- this->OptionLanguage = "C++";
+ this->Reporter.OptionLanguage = arg;
+ if (this->Reporter.OptionLanguage == "CXX") {
+ this->Reporter.OptionLanguage = "C++";
}
doing = DoingNone;
} else if (doing == DoingTargetName) {
- this->OptionTargetName = arg;
+ this->Reporter.OptionTargetName = arg;
doing = DoingNone;
} else if (doing == DoingTargetType) {
- this->OptionTargetType = arg;
+ this->Reporter.OptionTargetType = arg;
doing = DoingNone;
} else if (doing == DoingBuildDir) {
- this->OptionBuildDir = arg;
+ this->Reporter.OptionBuildDir = arg;
doing = DoingNone;
} else if (doing == DoingFilterPrefix) {
- this->OptionFilterPrefix = arg;
+ this->Reporter.OptionFilterPrefix = arg;
doing = DoingNone;
}
}
@@ -150,42 +141,11 @@ void cmCTestLaunch::HandleRealArg(const char* arg)
this->RealArgs.emplace_back(arg);
}
-void cmCTestLaunch::ComputeFileNames()
-{
- // We just passthru the behavior of the real command unless the
- // CTEST_LAUNCH_LOGS environment variable is set.
- const char* d = getenv("CTEST_LAUNCH_LOGS");
- if (!(d && *d)) {
- return;
- }
- this->Passthru = false;
-
- // The environment variable specifies the directory into which we
- // generate build logs.
- this->LogDir = d;
- cmSystemTools::ConvertToUnixSlashes(this->LogDir);
- this->LogDir += "/";
-
- // We hash the input command working dir and command line to obtain
- // a repeatable and (probably) unique name for log files.
- cmCryptoHash md5(cmCryptoHash::AlgoMD5);
- md5.Initialize();
- md5.Append(this->CWD);
- for (std::string const& realArg : this->RealArgs) {
- md5.Append(realArg);
- }
- this->LogHash = md5.FinalizeHex();
-
- // We store stdout and stderr in temporary log files.
- this->LogOut = cmStrCat(this->LogDir, "launch-", this->LogHash, "-out.txt");
- this->LogErr = cmStrCat(this->LogDir, "launch-", this->LogHash, "-err.txt");
-}
-
void cmCTestLaunch::RunChild()
{
// Ignore noopt make rules
if (this->RealArgs.empty() || this->RealArgs[0] == ":") {
- this->ExitCode = 0;
+ this->Reporter.ExitCode = 0;
return;
}
@@ -195,14 +155,14 @@ void cmCTestLaunch::RunChild()
cmsys::ofstream fout;
cmsys::ofstream ferr;
- if (this->Passthru) {
+ if (this->Reporter.Passthru) {
// In passthru mode we just share the output pipes.
cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDOUT, 1);
cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDERR, 1);
} else {
// In full mode we record the child output pipes to log files.
- fout.open(this->LogOut.c_str(), std::ios::out | std::ios::binary);
- ferr.open(this->LogErr.c_str(), std::ios::out | std::ios::binary);
+ fout.open(this->Reporter.LogOut.c_str(), std::ios::out | std::ios::binary);
+ ferr.open(this->Reporter.LogErr.c_str(), std::ios::out | std::ios::binary);
}
#ifdef _WIN32
@@ -216,7 +176,7 @@ void cmCTestLaunch::RunChild()
cmsysProcess_Execute(cp);
// Record child stdout and stderr if necessary.
- if (!this->Passthru) {
+ if (!this->Reporter.Passthru) {
char* data = nullptr;
int length = 0;
cmProcessOutput processOutput;
@@ -248,7 +208,7 @@ void cmCTestLaunch::RunChild()
// Wait for the real command to finish.
cmsysProcess_WaitForExit(cp, nullptr);
- this->ExitCode = cmsysProcess_GetExitValue(cp);
+ this->Reporter.ExitCode = cmsysProcess_GetExitValue(cp);
}
int cmCTestLaunch::Run()
@@ -261,255 +221,31 @@ int cmCTestLaunch::Run()
this->RunChild();
if (this->CheckResults()) {
- return this->ExitCode;
+ return this->Reporter.ExitCode;
}
this->LoadConfig();
- this->WriteXML();
-
- return this->ExitCode;
-}
-
-void cmCTestLaunch::LoadLabels()
-{
- if (this->OptionBuildDir.empty() || this->OptionTargetName.empty()) {
- return;
- }
-
- // Labels are listed in per-target files.
- std::string fname = cmStrCat(this->OptionBuildDir, "/CMakeFiles/",
- this->OptionTargetName, ".dir/Labels.txt");
-
- // We are interested in per-target labels for this source file.
- std::string source = this->OptionSource;
- cmSystemTools::ConvertToUnixSlashes(source);
-
- // Load the labels file.
- cmsys::ifstream fin(fname.c_str(), std::ios::in | std::ios::binary);
- if (!fin) {
- return;
- }
- bool inTarget = true;
- bool inSource = false;
- std::string line;
- while (cmSystemTools::GetLineFromStream(fin, line)) {
- if (line.empty() || line[0] == '#') {
- // Ignore blank and comment lines.
- continue;
- }
- if (line[0] == ' ') {
- // Label lines appear indented by one space.
- if (inTarget || inSource) {
- this->Labels.insert(line.substr(1));
- }
- } else if (!this->OptionSource.empty() && !inSource) {
- // Non-indented lines specify a source file name. The first one
- // is the end of the target-wide labels. Use labels following a
- // matching source.
- inTarget = false;
- inSource = this->SourceMatches(line, source);
- } else {
- return;
- }
- }
-}
-
-bool cmCTestLaunch::SourceMatches(std::string const& lhs,
- std::string const& rhs)
-{
- // TODO: Case sensitivity, UseRelativePaths, etc. Note that both
- // paths in the comparison get generated by CMake. This is done for
- // every source in the target, so it should be efficient (cannot use
- // cmSystemTools::IsSameFile).
- return lhs == rhs;
-}
-
-bool cmCTestLaunch::IsError() const
-{
- return this->ExitCode != 0;
-}
-
-void cmCTestLaunch::WriteXML()
-{
- // Name the xml file.
- std::string logXML =
- cmStrCat(this->LogDir, this->IsError() ? "error-" : "warning-",
- this->LogHash, ".xml");
-
- // Use cmGeneratedFileStream to atomically create the report file.
- cmGeneratedFileStream fxml(logXML);
- cmXMLWriter xml(fxml, 2);
- cmXMLElement e2(xml, "Failure");
- e2.Attribute("type", this->IsError() ? "Error" : "Warning");
- this->WriteXMLAction(e2);
- this->WriteXMLCommand(e2);
- this->WriteXMLResult(e2);
- this->WriteXMLLabels(e2);
-}
-
-void cmCTestLaunch::WriteXMLAction(cmXMLElement& e2)
-{
- e2.Comment("Meta-information about the build action");
- cmXMLElement e3(e2, "Action");
-
- // TargetName
- if (!this->OptionTargetName.empty()) {
- e3.Element("TargetName", this->OptionTargetName);
- }
-
- // Language
- if (!this->OptionLanguage.empty()) {
- e3.Element("Language", this->OptionLanguage);
- }
-
- // SourceFile
- if (!this->OptionSource.empty()) {
- std::string source = this->OptionSource;
- cmSystemTools::ConvertToUnixSlashes(source);
-
- // If file is in source tree use its relative location.
- if (cmSystemTools::FileIsFullPath(this->SourceDir) &&
- cmSystemTools::FileIsFullPath(source) &&
- cmSystemTools::IsSubDirectory(source, this->SourceDir)) {
- source = cmSystemTools::RelativePath(this->SourceDir, source);
- }
-
- e3.Element("SourceFile", source);
- }
-
- // OutputFile
- if (!this->OptionOutput.empty()) {
- e3.Element("OutputFile", this->OptionOutput);
- }
-
- // OutputType
- const char* outputType = nullptr;
- if (!this->OptionTargetType.empty()) {
- if (this->OptionTargetType == "EXECUTABLE") {
- outputType = "executable";
- } else if (this->OptionTargetType == "SHARED_LIBRARY") {
- outputType = "shared library";
- } else if (this->OptionTargetType == "MODULE_LIBRARY") {
- outputType = "module library";
- } else if (this->OptionTargetType == "STATIC_LIBRARY") {
- outputType = "static library";
- }
- } else if (!this->OptionSource.empty()) {
- outputType = "object file";
- }
- if (outputType) {
- e3.Element("OutputType", outputType);
- }
-}
-
-void cmCTestLaunch::WriteXMLCommand(cmXMLElement& e2)
-{
- e2.Comment("Details of command");
- cmXMLElement e3(e2, "Command");
- if (!this->CWD.empty()) {
- e3.Element("WorkingDirectory", this->CWD);
- }
- for (std::string const& realArg : this->RealArgs) {
- e3.Element("Argument", realArg);
- }
-}
-
-void cmCTestLaunch::WriteXMLResult(cmXMLElement& e2)
-{
- e2.Comment("Result of command");
- cmXMLElement e3(e2, "Result");
-
- // StdOut
- this->DumpFileToXML(e3, "StdOut", this->LogOut);
-
- // StdErr
- this->DumpFileToXML(e3, "StdErr", this->LogErr);
-
- // ExitCondition
- cmXMLElement e4(e3, "ExitCondition");
- cmsysProcess* cp = this->Process;
- switch (cmsysProcess_GetState(cp)) {
- case cmsysProcess_State_Starting:
- e4.Content("No process has been executed");
- break;
- case cmsysProcess_State_Executing:
- e4.Content("The process is still executing");
- break;
- case cmsysProcess_State_Disowned:
- e4.Content("Disowned");
- break;
- case cmsysProcess_State_Killed:
- e4.Content("Killed by parent");
- break;
-
- case cmsysProcess_State_Expired:
- e4.Content("Killed when timeout expired");
- break;
- case cmsysProcess_State_Exited:
- e4.Content(this->ExitCode);
- break;
- case cmsysProcess_State_Exception:
- e4.Content("Terminated abnormally: ");
- e4.Content(cmsysProcess_GetExceptionString(cp));
- break;
- case cmsysProcess_State_Error:
- e4.Content("Error administrating child process: ");
- e4.Content(cmsysProcess_GetErrorString(cp));
- break;
- }
-}
+ this->Reporter.Process = this->Process;
+ this->Reporter.WriteXML();
-void cmCTestLaunch::WriteXMLLabels(cmXMLElement& e2)
-{
- this->LoadLabels();
- if (!this->Labels.empty()) {
- e2.Comment("Interested parties");
- cmXMLElement e3(e2, "Labels");
- for (std::string const& label : this->Labels) {
- e3.Element("Label", label);
- }
- }
-}
-
-void cmCTestLaunch::DumpFileToXML(cmXMLElement& e3, const char* tag,
- std::string const& fname)
-{
- cmsys::ifstream fin(fname.c_str(), std::ios::in | std::ios::binary);
-
- std::string line;
- const char* sep = "";
-
- cmXMLElement e4(e3, tag);
- while (cmSystemTools::GetLineFromStream(fin, line)) {
- if (MatchesFilterPrefix(line)) {
- continue;
- }
- if (this->Match(line, this->RegexWarningSuppress)) {
- line = cmStrCat("[CTest: warning suppressed] ", line);
- } else if (this->Match(line, this->RegexWarning)) {
- line = cmStrCat("[CTest: warning matched] ", line);
- }
- e4.Content(sep);
- e4.Content(line);
- sep = "\n";
- }
+ return this->Reporter.ExitCode;
}
bool cmCTestLaunch::CheckResults()
{
// Skip XML in passthru mode.
- if (this->Passthru) {
+ if (this->Reporter.Passthru) {
return true;
}
// We always report failure for error conditions.
- if (this->IsError()) {
+ if (this->Reporter.IsError()) {
return false;
}
// Scrape the output logs to look for warnings.
- if ((this->HaveErr && this->ScrapeLog(this->LogErr)) ||
- (this->HaveOut && this->ScrapeLog(this->LogOut))) {
+ if ((this->HaveErr && this->ScrapeLog(this->Reporter.LogErr)) ||
+ (this->HaveOut && this->ScrapeLog(this->Reporter.LogOut))) {
return false;
}
return true;
@@ -522,22 +258,17 @@ void cmCTestLaunch::LoadScrapeRules()
}
this->ScrapeRulesLoaded = true;
- // Common compiler warning formats. These are much simpler than the
- // full log-scraping expressions because we do not need to extract
- // file and line information.
- this->RegexWarning.emplace_back("(^|[ :])[Ww][Aa][Rr][Nn][Ii][Nn][Gg]");
- this->RegexWarning.emplace_back("(^|[ :])[Rr][Ee][Mm][Aa][Rr][Kk]");
- this->RegexWarning.emplace_back("(^|[ :])[Nn][Oo][Tt][Ee]");
-
// Load custom match rules given to us by CTest.
- this->LoadScrapeRules("Warning", this->RegexWarning);
- this->LoadScrapeRules("WarningSuppress", this->RegexWarningSuppress);
+ this->LoadScrapeRules("Warning", this->Reporter.RegexWarning);
+ this->LoadScrapeRules("WarningSuppress",
+ this->Reporter.RegexWarningSuppress);
}
void cmCTestLaunch::LoadScrapeRules(
const char* purpose, std::vector<cmsys::RegularExpression>& regexps)
{
- std::string fname = cmStrCat(this->LogDir, "Custom", purpose, ".txt");
+ std::string fname =
+ cmStrCat(this->Reporter.LogDir, "Custom", purpose, ".txt");
cmsys::ifstream fin(fname.c_str(), std::ios::in | std::ios::binary);
std::string line;
cmsys::RegularExpression rex;
@@ -557,35 +288,18 @@ bool cmCTestLaunch::ScrapeLog(std::string const& fname)
cmsys::ifstream fin(fname.c_str(), std::ios::in | std::ios::binary);
std::string line;
while (cmSystemTools::GetLineFromStream(fin, line)) {
- if (MatchesFilterPrefix(line)) {
+ if (this->Reporter.MatchesFilterPrefix(line)) {
continue;
}
- if (this->Match(line, this->RegexWarning) &&
- !this->Match(line, this->RegexWarningSuppress)) {
+ if (this->Reporter.Match(line, this->Reporter.RegexWarning) &&
+ !this->Reporter.Match(line, this->Reporter.RegexWarningSuppress)) {
return true;
}
}
return false;
}
-bool cmCTestLaunch::Match(std::string const& line,
- std::vector<cmsys::RegularExpression>& regexps)
-{
- for (cmsys::RegularExpression& r : regexps) {
- if (r.find(line)) {
- return true;
- }
- }
- return false;
-}
-
-bool cmCTestLaunch::MatchesFilterPrefix(std::string const& line) const
-{
- return !this->OptionFilterPrefix.empty() &&
- cmHasPrefix(line, this->OptionFilterPrefix);
-}
-
int cmCTestLaunch::Main(int argc, const char* const argv[])
{
if (argc == 2) {
@@ -605,9 +319,10 @@ void cmCTestLaunch::LoadConfig()
cm.GetCurrentSnapshot().SetDefaultDefinitions();
cmGlobalGenerator gg(&cm);
cmMakefile mf(&gg, cm.GetCurrentSnapshot());
- std::string fname = cmStrCat(this->LogDir, "CTestLaunchConfig.cmake");
+ std::string fname =
+ cmStrCat(this->Reporter.LogDir, "CTestLaunchConfig.cmake");
if (cmSystemTools::FileExists(fname) && mf.ReadListFile(fname)) {
- this->SourceDir = mf.GetSafeDefinition("CTEST_SOURCE_DIRECTORY");
- cmSystemTools::ConvertToUnixSlashes(this->SourceDir);
+ this->Reporter.SourceDir = mf.GetSafeDefinition("CTEST_SOURCE_DIRECTORY");
+ cmSystemTools::ConvertToUnixSlashes(this->Reporter.SourceDir);
}
}
diff --git a/Source/CTest/cmCTestLaunch.h b/Source/CTest/cmCTestLaunch.h
index 33ff82c..d18f66d 100644
--- a/Source/CTest/cmCTestLaunch.h
+++ b/Source/CTest/cmCTestLaunch.h
@@ -4,13 +4,14 @@
#include "cmConfigure.h" // IWYU pragma: keep
-#include <set>
#include <string>
#include <vector>
-#include "cmsys/RegularExpression.hxx"
+#include "cmCTestLaunchReporter.h"
-class cmXMLElement;
+namespace cmsys {
+class RegularExpression;
+}
/** \class cmCTestLaunch
* \brief Launcher for make rules to report results for ctest
@@ -35,70 +36,36 @@ private:
int Run();
void RunChild();
- // Methods to check the result of the real command.
- bool IsError() const;
+ // Method to check the result of the real command.
bool CheckResults();
- // Launcher options specified before the real command.
- std::string OptionOutput;
- std::string OptionSource;
- std::string OptionLanguage;
- std::string OptionTargetName;
- std::string OptionTargetType;
- std::string OptionBuildDir;
- std::string OptionFilterPrefix;
+ // Parse out launcher-specific options specified before the real command.
bool ParseArguments(int argc, const char* const* argv);
// The real command line appearing after launcher arguments.
int RealArgC;
const char* const* RealArgV;
- std::string CWD;
// The real command line after response file expansion.
std::vector<std::string> RealArgs;
void HandleRealArg(const char* arg);
- // A hash of the real command line is unique and unlikely to collide.
- std::string LogHash;
- void ComputeFileNames();
-
- bool Passthru;
struct cmsysProcess_s* Process;
- int ExitCode;
- // Temporary log files for stdout and stderr of real command.
- std::string LogDir;
- std::string LogOut;
- std::string LogErr;
+ // Whether or not any data have been written to stdout or stderr.
bool HaveOut;
bool HaveErr;
- // Labels associated with the build rule.
- std::set<std::string> Labels;
- void LoadLabels();
- bool SourceMatches(std::string const& lhs, std::string const& rhs);
-
- // Regular expressions to match warnings and their exceptions.
+ // Load custom rules to match warnings and their exceptions.
bool ScrapeRulesLoaded;
- std::vector<cmsys::RegularExpression> RegexWarning;
- std::vector<cmsys::RegularExpression> RegexWarningSuppress;
void LoadScrapeRules();
void LoadScrapeRules(const char* purpose,
std::vector<cmsys::RegularExpression>& regexps);
bool ScrapeLog(std::string const& fname);
- bool Match(std::string const& line,
- std::vector<cmsys::RegularExpression>& regexps);
- bool MatchesFilterPrefix(std::string const& line) const;
-
- // Methods to generate the xml fragment.
- void WriteXML();
- void WriteXMLAction(cmXMLElement&);
- void WriteXMLCommand(cmXMLElement&);
- void WriteXMLResult(cmXMLElement&);
- void WriteXMLLabels(cmXMLElement&);
- void DumpFileToXML(cmXMLElement&, const char* tag, std::string const& fname);
+
+ // Helper class to generate the xml fragment.
+ cmCTestLaunchReporter Reporter;
// Configuration
void LoadConfig();
- std::string SourceDir;
};
diff --git a/Source/CTest/cmCTestLaunchReporter.cxx b/Source/CTest/cmCTestLaunchReporter.cxx
new file mode 100644
index 0000000..6ec7d0e
--- /dev/null
+++ b/Source/CTest/cmCTestLaunchReporter.cxx
@@ -0,0 +1,316 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestLaunchReporter.h"
+
+#include "cmsys/FStream.hxx"
+#include "cmsys/Process.h"
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmCryptoHash.h"
+#include "cmGeneratedFileStream.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmXMLWriter.h"
+
+#ifdef _WIN32
+# include <fcntl.h> // for _O_BINARY
+# include <io.h> // for _setmode
+# include <stdio.h> // for std{out,err} and fileno
+#endif
+
+cmCTestLaunchReporter::cmCTestLaunchReporter()
+{
+ this->Passthru = true;
+ this->ExitCode = 1;
+ this->CWD = cmSystemTools::GetCurrentWorkingDirectory();
+
+ this->ComputeFileNames();
+
+ // Common compiler warning formats. These are much simpler than the
+ // full log-scraping expressions because we do not need to extract
+ // file and line information.
+ this->RegexWarning.emplace_back("(^|[ :])[Ww][Aa][Rr][Nn][Ii][Nn][Gg]");
+ this->RegexWarning.emplace_back("(^|[ :])[Rr][Ee][Mm][Aa][Rr][Kk]");
+ this->RegexWarning.emplace_back("(^|[ :])[Nn][Oo][Tt][Ee]");
+}
+
+cmCTestLaunchReporter::~cmCTestLaunchReporter()
+{
+ if (!this->Passthru) {
+ cmSystemTools::RemoveFile(this->LogOut);
+ cmSystemTools::RemoveFile(this->LogErr);
+ }
+}
+
+void cmCTestLaunchReporter::ComputeFileNames()
+{
+ // We just passthru the behavior of the real command unless the
+ // CTEST_LAUNCH_LOGS environment variable is set.
+ std::string d;
+ if (!cmSystemTools::GetEnv("CTEST_LAUNCH_LOGS", d) || d.empty()) {
+ return;
+ }
+ this->Passthru = false;
+
+ // The environment variable specifies the directory into which we
+ // generate build logs.
+ this->LogDir = d;
+ cmSystemTools::ConvertToUnixSlashes(this->LogDir);
+ this->LogDir += "/";
+
+ // We hash the input command working dir and command line to obtain
+ // a repeatable and (probably) unique name for log files.
+ cmCryptoHash md5(cmCryptoHash::AlgoMD5);
+ md5.Initialize();
+ md5.Append(this->CWD);
+ for (std::string const& realArg : this->RealArgs) {
+ md5.Append(realArg);
+ }
+ this->LogHash = md5.FinalizeHex();
+
+ // We store stdout and stderr in temporary log files.
+ this->LogOut = cmStrCat(this->LogDir, "launch-", this->LogHash, "-out.txt");
+ this->LogErr = cmStrCat(this->LogDir, "launch-", this->LogHash, "-err.txt");
+}
+
+void cmCTestLaunchReporter::LoadLabels()
+{
+ if (this->OptionBuildDir.empty() || this->OptionTargetName.empty()) {
+ return;
+ }
+
+ // Labels are listed in per-target files.
+ std::string fname = cmStrCat(this->OptionBuildDir, "/CMakeFiles/",
+ this->OptionTargetName, ".dir/Labels.txt");
+
+ // We are interested in per-target labels for this source file.
+ std::string source = this->OptionSource;
+ cmSystemTools::ConvertToUnixSlashes(source);
+
+ // Load the labels file.
+ cmsys::ifstream fin(fname.c_str(), std::ios::in | std::ios::binary);
+ if (!fin) {
+ return;
+ }
+ bool inTarget = true;
+ bool inSource = false;
+ std::string line;
+ while (cmSystemTools::GetLineFromStream(fin, line)) {
+ if (line.empty() || line[0] == '#') {
+ // Ignore blank and comment lines.
+ continue;
+ }
+ if (line[0] == ' ') {
+ // Label lines appear indented by one space.
+ if (inTarget || inSource) {
+ this->Labels.insert(line.substr(1));
+ }
+ } else if (!this->OptionSource.empty() && !inSource) {
+ // Non-indented lines specify a source file name. The first one
+ // is the end of the target-wide labels. Use labels following a
+ // matching source.
+ inTarget = false;
+ inSource = this->SourceMatches(line, source);
+ } else {
+ return;
+ }
+ }
+}
+
+bool cmCTestLaunchReporter::SourceMatches(std::string const& lhs,
+ std::string const& rhs)
+{
+ // TODO: Case sensitivity, UseRelativePaths, etc. Note that both
+ // paths in the comparison get generated by CMake. This is done for
+ // every source in the target, so it should be efficient (cannot use
+ // cmSystemTools::IsSameFile).
+ return lhs == rhs;
+}
+
+bool cmCTestLaunchReporter::IsError() const
+{
+ return this->ExitCode != 0;
+}
+
+void cmCTestLaunchReporter::WriteXML()
+{
+ // Name the xml file.
+ std::string logXML =
+ cmStrCat(this->LogDir, this->IsError() ? "error-" : "warning-",
+ this->LogHash, ".xml");
+
+ // Use cmGeneratedFileStream to atomically create the report file.
+ cmGeneratedFileStream fxml(logXML);
+ cmXMLWriter xml(fxml, 2);
+ cmXMLElement e2(xml, "Failure");
+ e2.Attribute("type", this->IsError() ? "Error" : "Warning");
+ this->WriteXMLAction(e2);
+ this->WriteXMLCommand(e2);
+ this->WriteXMLResult(e2);
+ this->WriteXMLLabels(e2);
+}
+
+void cmCTestLaunchReporter::WriteXMLAction(cmXMLElement& e2)
+{
+ e2.Comment("Meta-information about the build action");
+ cmXMLElement e3(e2, "Action");
+
+ // TargetName
+ if (!this->OptionTargetName.empty()) {
+ e3.Element("TargetName", this->OptionTargetName);
+ }
+
+ // Language
+ if (!this->OptionLanguage.empty()) {
+ e3.Element("Language", this->OptionLanguage);
+ }
+
+ // SourceFile
+ if (!this->OptionSource.empty()) {
+ std::string source = this->OptionSource;
+ cmSystemTools::ConvertToUnixSlashes(source);
+
+ // If file is in source tree use its relative location.
+ if (cmSystemTools::FileIsFullPath(this->SourceDir) &&
+ cmSystemTools::FileIsFullPath(source) &&
+ cmSystemTools::IsSubDirectory(source, this->SourceDir)) {
+ source = cmSystemTools::RelativePath(this->SourceDir, source);
+ }
+
+ e3.Element("SourceFile", source);
+ }
+
+ // OutputFile
+ if (!this->OptionOutput.empty()) {
+ e3.Element("OutputFile", this->OptionOutput);
+ }
+
+ // OutputType
+ const char* outputType = nullptr;
+ if (!this->OptionTargetType.empty()) {
+ if (this->OptionTargetType == "EXECUTABLE") {
+ outputType = "executable";
+ } else if (this->OptionTargetType == "SHARED_LIBRARY") {
+ outputType = "shared library";
+ } else if (this->OptionTargetType == "MODULE_LIBRARY") {
+ outputType = "module library";
+ } else if (this->OptionTargetType == "STATIC_LIBRARY") {
+ outputType = "static library";
+ }
+ } else if (!this->OptionSource.empty()) {
+ outputType = "object file";
+ }
+ if (outputType) {
+ e3.Element("OutputType", outputType);
+ }
+}
+
+void cmCTestLaunchReporter::WriteXMLCommand(cmXMLElement& e2)
+{
+ e2.Comment("Details of command");
+ cmXMLElement e3(e2, "Command");
+ if (!this->CWD.empty()) {
+ e3.Element("WorkingDirectory", this->CWD);
+ }
+ for (std::string const& realArg : this->RealArgs) {
+ e3.Element("Argument", realArg);
+ }
+}
+
+void cmCTestLaunchReporter::WriteXMLResult(cmXMLElement& e2)
+{
+ e2.Comment("Result of command");
+ cmXMLElement e3(e2, "Result");
+
+ // StdOut
+ this->DumpFileToXML(e3, "StdOut", this->LogOut);
+
+ // StdErr
+ this->DumpFileToXML(e3, "StdErr", this->LogErr);
+
+ // ExitCondition
+ cmXMLElement e4(e3, "ExitCondition");
+ cmsysProcess* cp = this->Process;
+ switch (cmsysProcess_GetState(cp)) {
+ case cmsysProcess_State_Starting:
+ e4.Content("No process has been executed");
+ break;
+ case cmsysProcess_State_Executing:
+ e4.Content("The process is still executing");
+ break;
+ case cmsysProcess_State_Disowned:
+ e4.Content("Disowned");
+ break;
+ case cmsysProcess_State_Killed:
+ e4.Content("Killed by parent");
+ break;
+
+ case cmsysProcess_State_Expired:
+ e4.Content("Killed when timeout expired");
+ break;
+ case cmsysProcess_State_Exited:
+ e4.Content(this->ExitCode);
+ break;
+ case cmsysProcess_State_Exception:
+ e4.Content("Terminated abnormally: ");
+ e4.Content(cmsysProcess_GetExceptionString(cp));
+ break;
+ case cmsysProcess_State_Error:
+ e4.Content("Error administrating child process: ");
+ e4.Content(cmsysProcess_GetErrorString(cp));
+ break;
+ }
+}
+
+void cmCTestLaunchReporter::WriteXMLLabels(cmXMLElement& e2)
+{
+ this->LoadLabels();
+ if (!this->Labels.empty()) {
+ e2.Comment("Interested parties");
+ cmXMLElement e3(e2, "Labels");
+ for (std::string const& label : this->Labels) {
+ e3.Element("Label", label);
+ }
+ }
+}
+
+void cmCTestLaunchReporter::DumpFileToXML(cmXMLElement& e3, const char* tag,
+ std::string const& fname)
+{
+ cmsys::ifstream fin(fname.c_str(), std::ios::in | std::ios::binary);
+
+ std::string line;
+ const char* sep = "";
+
+ cmXMLElement e4(e3, tag);
+ while (cmSystemTools::GetLineFromStream(fin, line)) {
+ if (MatchesFilterPrefix(line)) {
+ continue;
+ }
+ if (this->Match(line, this->RegexWarningSuppress)) {
+ line = cmStrCat("[CTest: warning suppressed] ", line);
+ } else if (this->Match(line, this->RegexWarning)) {
+ line = cmStrCat("[CTest: warning matched] ", line);
+ }
+ e4.Content(sep);
+ e4.Content(line);
+ sep = "\n";
+ }
+}
+
+bool cmCTestLaunchReporter::Match(
+ std::string const& line, std::vector<cmsys::RegularExpression>& regexps)
+{
+ for (cmsys::RegularExpression& r : regexps) {
+ if (r.find(line)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool cmCTestLaunchReporter::MatchesFilterPrefix(std::string const& line) const
+{
+ return !this->OptionFilterPrefix.empty() &&
+ cmHasPrefix(line, this->OptionFilterPrefix);
+}
diff --git a/Source/CTest/cmCTestLaunchReporter.h b/Source/CTest/cmCTestLaunchReporter.h
new file mode 100644
index 0000000..675a878
--- /dev/null
+++ b/Source/CTest/cmCTestLaunchReporter.h
@@ -0,0 +1,81 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include "cmsys/RegularExpression.hxx"
+
+class cmXMLElement;
+
+/** \class cmCTestLaunchReporter
+ * \brief Generate CTest XML output for the 'ctest --launch' tool.
+ */
+class cmCTestLaunchReporter
+{
+public:
+ // Initialize the launcher from its command line.
+ cmCTestLaunchReporter();
+ ~cmCTestLaunchReporter();
+
+ cmCTestLaunchReporter(const cmCTestLaunchReporter&) = delete;
+ cmCTestLaunchReporter& operator=(const cmCTestLaunchReporter&) = delete;
+
+ // Methods to check the result of the real command.
+ bool IsError() const;
+
+ // Launcher options specified before the real command.
+ std::string OptionOutput;
+ std::string OptionSource;
+ std::string OptionLanguage;
+ std::string OptionTargetName;
+ std::string OptionTargetType;
+ std::string OptionBuildDir;
+ std::string OptionFilterPrefix;
+
+ // The real command line appearing after launcher arguments.
+ std::string CWD;
+
+ // The real command line after response file expansion.
+ std::vector<std::string> RealArgs;
+
+ // A hash of the real command line is unique and unlikely to collide.
+ std::string LogHash;
+ void ComputeFileNames();
+
+ bool Passthru;
+ struct cmsysProcess_s* Process;
+ int ExitCode;
+
+ // Temporary log files for stdout and stderr of real command.
+ std::string LogDir;
+ std::string LogOut;
+ std::string LogErr;
+
+ // Labels associated with the build rule.
+ std::set<std::string> Labels;
+ void LoadLabels();
+ bool SourceMatches(std::string const& lhs, std::string const& rhs);
+
+ // Regular expressions to match warnings and their exceptions.
+ std::vector<cmsys::RegularExpression> RegexWarning;
+ std::vector<cmsys::RegularExpression> RegexWarningSuppress;
+ bool Match(std::string const& line,
+ std::vector<cmsys::RegularExpression>& regexps);
+ bool MatchesFilterPrefix(std::string const& line) const;
+
+ // Methods to generate the xml fragment.
+ void WriteXML();
+ void WriteXMLAction(cmXMLElement&);
+ void WriteXMLCommand(cmXMLElement&);
+ void WriteXMLResult(cmXMLElement&);
+ void WriteXMLLabels(cmXMLElement&);
+ void DumpFileToXML(cmXMLElement&, const char* tag, std::string const& fname);
+
+ // Configuration
+ std::string SourceDir;
+};
diff --git a/Source/QtDialog/AddCacheEntry.cxx b/Source/QtDialog/AddCacheEntry.cxx
index f5e0777..1075895 100644
--- a/Source/QtDialog/AddCacheEntry.cxx
+++ b/Source/QtDialog/AddCacheEntry.cxx
@@ -40,8 +40,10 @@ AddCacheEntry::AddCacheEntry(QWidget* p, const QStringList& varNames,
AddCacheEntry::setTabOrder(string, this->Description);
QCompleter* completer = new QCompleter(this->VarNames, this);
this->Name->setCompleter(completer);
- connect(completer, SIGNAL(activated(const QString&)), this,
- SLOT(onCompletionActivated(const QString&)));
+ connect(
+ completer,
+ static_cast<void (QCompleter::*)(const QString&)>(&QCompleter::activated),
+ this, &AddCacheEntry::onCompletionActivated);
}
QString AddCacheEntry::name() const
diff --git a/Source/QtDialog/CMakeLists.txt b/Source/QtDialog/CMakeLists.txt
index 0ec012c..5fd0e89 100644
--- a/Source/QtDialog/CMakeLists.txt
+++ b/Source/QtDialog/CMakeLists.txt
@@ -84,6 +84,8 @@ set(SRCS
CMakeSetupDialog.cxx
CMakeSetupDialog.h
Compilers.h
+ EnvironmentDialog.cxx
+ EnvironmentDialog.h
FirstConfigure.cxx
FirstConfigure.h
QCMake.cxx
@@ -102,6 +104,7 @@ qt5_wrap_ui(UI_SRCS
Compilers.ui
CrossCompiler.ui
AddCacheEntry.ui
+ EnvironmentDialog.ui
RegexExplorer.ui
WarningMessagesDialog.ui
)
@@ -109,6 +112,7 @@ qt5_wrap_cpp(MOC_SRCS
AddCacheEntry.h
Compilers.h
CMakeSetupDialog.h
+ EnvironmentDialog.h
FirstConfigure.h
QCMake.h
QCMakeCacheView.h
diff --git a/Source/QtDialog/CMakeSetupDialog.cxx b/Source/QtDialog/CMakeSetupDialog.cxx
index fcc8408..a904b94 100644
--- a/Source/QtDialog/CMakeSetupDialog.cxx
+++ b/Source/QtDialog/CMakeSetupDialog.cxx
@@ -16,6 +16,7 @@
#include <QMenuBar>
#include <QMessageBox>
#include <QMimeData>
+#include <QProcessEnvironment>
#include <QProgressBar>
#include <QSettings>
#include <QShortcut>
@@ -35,6 +36,7 @@
#include "cmVersion.h"
#include "AddCacheEntry.h"
+#include "EnvironmentDialog.h"
#include "FirstConfigure.h"
#include "RegexExplorer.h"
#include "WarningMessagesDialog.h"
@@ -103,76 +105,87 @@ CMakeSetupDialog::CMakeSetupDialog()
QMenu* FileMenu = this->menuBar()->addMenu(tr("&File"));
this->ReloadCacheAction = FileMenu->addAction(tr("&Reload Cache"));
- QObject::connect(this->ReloadCacheAction, SIGNAL(triggered(bool)), this,
- SLOT(doReloadCache()));
+ QObject::connect(this->ReloadCacheAction, &QAction::triggered, this,
+ &CMakeSetupDialog::doReloadCache);
this->DeleteCacheAction = FileMenu->addAction(tr("&Delete Cache"));
- QObject::connect(this->DeleteCacheAction, SIGNAL(triggered(bool)), this,
- SLOT(doDeleteCache()));
+ QObject::connect(this->DeleteCacheAction, &QAction::triggered, this,
+ &CMakeSetupDialog::doDeleteCache);
this->ExitAction = FileMenu->addAction(tr("E&xit"));
- this->ExitAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q));
- QObject::connect(this->ExitAction, SIGNAL(triggered(bool)), this,
- SLOT(close()));
+ QObject::connect(this->ExitAction, &QAction::triggered, this,
+ &CMakeSetupDialog::close);
+ this->ExitAction->setShortcut(QKeySequence::Quit);
QMenu* ToolsMenu = this->menuBar()->addMenu(tr("&Tools"));
this->ConfigureAction = ToolsMenu->addAction(tr("&Configure"));
+ QObject::connect(this->ConfigureAction, &QAction::triggered, this,
+ &CMakeSetupDialog::doConfigure);
// prevent merging with Preferences menu item on macOS
this->ConfigureAction->setMenuRole(QAction::NoRole);
- QObject::connect(this->ConfigureAction, SIGNAL(triggered(bool)), this,
- SLOT(doConfigure()));
this->GenerateAction = ToolsMenu->addAction(tr("&Generate"));
- QObject::connect(this->GenerateAction, SIGNAL(triggered(bool)), this,
- SLOT(doGenerate()));
- QAction* showChangesAction = ToolsMenu->addAction(tr("&Show My Changes"));
- QObject::connect(showChangesAction, SIGNAL(triggered(bool)), this,
- SLOT(showUserChanges()));
+ QObject::connect(this->GenerateAction, &QAction::triggered, this,
+ &CMakeSetupDialog::doGenerate);
+ auto* a = ToolsMenu->addAction(tr("&Show My Changes"));
+ QObject::connect(a, &QAction::triggered, this,
+ &CMakeSetupDialog::showUserChanges);
#if defined(Q_WS_MAC) || defined(Q_OS_MAC)
this->InstallForCommandLineAction =
ToolsMenu->addAction(tr("&How to Install For Command Line Use"));
- QObject::connect(this->InstallForCommandLineAction, SIGNAL(triggered(bool)),
- this, SLOT(doInstallForCommandLine()));
+ QObject::connect(this->InstallForCommandLineAction, &QAction::triggered,
+ this, &CMakeSetupDialog::doInstallForCommandLine);
#endif
ToolsMenu->addSeparator();
- ToolsMenu->addAction(tr("Regular Expression Explorer..."), this,
- SLOT(doRegexExplorerDialog()));
+ a = ToolsMenu->addAction(tr("Regular Expression Explorer..."));
+ QObject::connect(a, &QAction::triggered, this,
+ &CMakeSetupDialog::doRegexExplorerDialog);
ToolsMenu->addSeparator();
- ToolsMenu->addAction(tr("&Find in Output..."), this,
- SLOT(doOutputFindDialog()), QKeySequence::Find);
- ToolsMenu->addAction(tr("Find Next"), this, SLOT(doOutputFindNext()),
- QKeySequence::FindNext);
- ToolsMenu->addAction(tr("Find Previous"), this, SLOT(doOutputFindPrev()),
- QKeySequence::FindPrevious);
- ToolsMenu->addAction(tr("Goto Next Error"), this, SLOT(doOutputErrorNext()),
- QKeySequence(Qt::Key_F8)); // in Visual Studio
- new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Period), this,
- SLOT(doOutputErrorNext())); // in Eclipse
+ a = ToolsMenu->addAction(tr("&Find in Output..."));
+ QObject::connect(a, &QAction::triggered, this,
+ &CMakeSetupDialog::doOutputFindDialog);
+ a->setShortcut(QKeySequence::Find);
+ a = ToolsMenu->addAction(tr("Find Next"));
+ QObject::connect(a, &QAction::triggered, this,
+ &CMakeSetupDialog::doOutputFindNext);
+ a->setShortcut(QKeySequence::FindNext);
+ a = ToolsMenu->addAction(tr("Find Previous"));
+ QObject::connect(a, &QAction::triggered, this,
+ &CMakeSetupDialog::doOutputFindPrev);
+ a->setShortcut(QKeySequence::FindPrevious);
+ a = ToolsMenu->addAction(tr("Goto Next Error")); // in Visual Studio
+ QObject::connect(a, &QAction::triggered, this,
+ &CMakeSetupDialog::doOutputErrorNext);
+ a->setShortcut(QKeySequence(Qt::Key_F8));
+ auto* s = new QShortcut(this);
+ s->setKey(QKeySequence(Qt::CTRL + Qt::Key_Period));
+ QObject::connect(s, &QShortcut::activated, this,
+ &CMakeSetupDialog::doOutputErrorNext); // in Eclipse
QMenu* OptionsMenu = this->menuBar()->addMenu(tr("&Options"));
- OptionsMenu->addAction(tr("Warning Messages..."), this,
- SLOT(doWarningMessagesDialog()));
+ a = OptionsMenu->addAction(tr("Warning Messages..."));
+ QObject::connect(a, &QAction::triggered, this,
+ &CMakeSetupDialog::doWarningMessagesDialog);
this->WarnUninitializedAction =
OptionsMenu->addAction(tr("&Warn Uninitialized (--warn-uninitialized)"));
this->WarnUninitializedAction->setCheckable(true);
QAction* debugAction = OptionsMenu->addAction(tr("&Debug Output"));
debugAction->setCheckable(true);
- QObject::connect(debugAction, SIGNAL(toggled(bool)), this,
- SLOT(setDebugOutput(bool)));
+ QObject::connect(debugAction, &QAction::toggled, this,
+ &CMakeSetupDialog::setDebugOutput);
OptionsMenu->addSeparator();
- QAction* expandAction =
- OptionsMenu->addAction(tr("&Expand Grouped Entries"));
- QObject::connect(expandAction, SIGNAL(triggered(bool)), this->CacheValues,
- SLOT(expandAll()));
- QAction* collapseAction =
- OptionsMenu->addAction(tr("&Collapse Grouped Entries"));
- QObject::connect(collapseAction, SIGNAL(triggered(bool)), this->CacheValues,
- SLOT(collapseAll()));
+ a = OptionsMenu->addAction(tr("&Expand Grouped Entries"));
+ QObject::connect(a, &QAction::triggered, this->CacheValues,
+ &QCMakeCacheView::expandAll);
+ a = OptionsMenu->addAction(tr("&Collapse Grouped Entries"));
+ QObject::connect(a, &QAction::triggered, this->CacheValues,
+ &QCMakeCacheView::collapseAll);
QMenu* HelpMenu = this->menuBar()->addMenu(tr("&Help"));
- QAction* a = HelpMenu->addAction(tr("About"));
- QObject::connect(a, SIGNAL(triggered(bool)), this, SLOT(doAbout()));
+ a = HelpMenu->addAction(tr("About"));
+ QObject::connect(a, &QAction::triggered, this, &CMakeSetupDialog::doAbout);
a = HelpMenu->addAction(tr("Help"));
- QObject::connect(a, SIGNAL(triggered(bool)), this, SLOT(doHelp()));
+ QObject::connect(a, &QAction::triggered, this, &CMakeSetupDialog::doHelp);
+ a->setShortcut(QKeySequence::HelpContents);
this->setAcceptDrops(true);
@@ -189,16 +202,16 @@ CMakeSetupDialog::CMakeSetupDialog()
this->ErrorFormat.setForeground(QBrush(Qt::red));
this->Output->setContextMenuPolicy(Qt::CustomContextMenu);
- connect(this->Output, SIGNAL(customContextMenuRequested(const QPoint&)),
- this, SLOT(doOutputContextMenu(const QPoint&)));
+ connect(this->Output, &QTextEdit::customContextMenuRequested, this,
+ &CMakeSetupDialog::doOutputContextMenu);
// disable open project button
this->OpenProjectButton->setDisabled(true);
// start the cmake worker thread
this->CMakeThread = new QCMakeThread(this);
- QObject::connect(this->CMakeThread, SIGNAL(cmakeInitialized()), this,
- SLOT(initialize()), Qt::QueuedConnection);
+ QObject::connect(this->CMakeThread, &QCMakeThread::cmakeInitialized, this,
+ &CMakeSetupDialog::initialize, Qt::QueuedConnection);
this->CMakeThread->start();
this->enterState(ReadyConfigure);
@@ -211,82 +224,82 @@ void CMakeSetupDialog::initialize()
{
// now the cmake worker thread is running, lets make our connections to it
QObject::connect(this->CMakeThread->cmakeInstance(),
- SIGNAL(propertiesChanged(const QCMakePropertyList&)),
- this->CacheValues->cacheModel(),
- SLOT(setProperties(const QCMakePropertyList&)));
+ &QCMake::propertiesChanged, this->CacheValues->cacheModel(),
+ &QCMakeCacheModel::setProperties);
- QObject::connect(this->ConfigureButton, SIGNAL(clicked(bool)), this,
- SLOT(doConfigure()));
+ QObject::connect(this->ConfigureButton, &QPushButton::clicked, this,
+ &CMakeSetupDialog::doConfigure);
- QObject::connect(this->CMakeThread->cmakeInstance(),
- SIGNAL(configureDone(int)), this, SLOT(exitLoop(int)));
- QObject::connect(this->CMakeThread->cmakeInstance(),
- SIGNAL(generateDone(int)), this, SLOT(exitLoop(int)));
+ QObject::connect(this->CMakeThread->cmakeInstance(), &QCMake::configureDone,
+ this, &CMakeSetupDialog::exitLoop);
+ QObject::connect(this->CMakeThread->cmakeInstance(), &QCMake::generateDone,
+ this, &CMakeSetupDialog::exitLoop);
- QObject::connect(this->GenerateButton, SIGNAL(clicked(bool)), this,
- SLOT(doGenerate()));
- QObject::connect(this->OpenProjectButton, SIGNAL(clicked(bool)), this,
- SLOT(doOpenProject()));
+ QObject::connect(this->GenerateButton, &QPushButton::clicked, this,
+ &CMakeSetupDialog::doGenerate);
+ QObject::connect(this->OpenProjectButton, &QPushButton::clicked, this,
+ &CMakeSetupDialog::doOpenProject);
- QObject::connect(this->BrowseSourceDirectoryButton, SIGNAL(clicked(bool)),
- this, SLOT(doSourceBrowse()));
- QObject::connect(this->BrowseBinaryDirectoryButton, SIGNAL(clicked(bool)),
- this, SLOT(doBinaryBrowse()));
+ QObject::connect(this->BrowseSourceDirectoryButton, &QPushButton::clicked,
+ this, &CMakeSetupDialog::doSourceBrowse);
+ QObject::connect(this->BrowseBinaryDirectoryButton, &QPushButton::clicked,
+ this, &CMakeSetupDialog::doBinaryBrowse);
- QObject::connect(this->BinaryDirectory, SIGNAL(editTextChanged(QString)),
- this, SLOT(onBinaryDirectoryChanged(QString)));
- QObject::connect(this->SourceDirectory, SIGNAL(textChanged(QString)), this,
- SLOT(onSourceDirectoryChanged(QString)));
+ QObject::connect(this->BinaryDirectory, &QComboBox::editTextChanged, this,
+ &CMakeSetupDialog::onBinaryDirectoryChanged);
+ QObject::connect(this->SourceDirectory, &QLineEdit::textChanged, this,
+ &CMakeSetupDialog::onSourceDirectoryChanged);
QObject::connect(this->CMakeThread->cmakeInstance(),
- SIGNAL(sourceDirChanged(QString)), this,
- SLOT(updateSourceDirectory(QString)));
+ &QCMake::sourceDirChanged, this,
+ &CMakeSetupDialog::updateSourceDirectory);
QObject::connect(this->CMakeThread->cmakeInstance(),
- SIGNAL(binaryDirChanged(QString)), this,
- SLOT(updateBinaryDirectory(QString)));
+ &QCMake::binaryDirChanged, this,
+ &CMakeSetupDialog::updateBinaryDirectory);
QObject::connect(this->CMakeThread->cmakeInstance(),
- SIGNAL(progressChanged(QString, float)), this,
- SLOT(showProgress(QString, float)));
+ &QCMake::progressChanged, this,
+ &CMakeSetupDialog::showProgress);
- QObject::connect(this->CMakeThread->cmakeInstance(),
- SIGNAL(errorMessage(QString)), this, SLOT(error(QString)));
+ QObject::connect(this->CMakeThread->cmakeInstance(), &QCMake::errorMessage,
+ this, &CMakeSetupDialog::error);
- QObject::connect(this->CMakeThread->cmakeInstance(),
- SIGNAL(outputMessage(QString)), this,
- SLOT(message(QString)));
+ QObject::connect(this->CMakeThread->cmakeInstance(), &QCMake::outputMessage,
+ this, &CMakeSetupDialog::message);
- QObject::connect(this->CMakeThread->cmakeInstance(),
- SIGNAL(openPossible(bool)), this->OpenProjectButton,
- SLOT(setEnabled(bool)));
+ QObject::connect(this->CMakeThread->cmakeInstance(), &QCMake::openPossible,
+ this->OpenProjectButton, &CMakeSetupDialog::setEnabled);
- QObject::connect(this->groupedCheck, SIGNAL(toggled(bool)), this,
- SLOT(setGroupedView(bool)));
- QObject::connect(this->advancedCheck, SIGNAL(toggled(bool)), this,
- SLOT(setAdvancedView(bool)));
- QObject::connect(this->Search, SIGNAL(textChanged(QString)), this,
- SLOT(setSearchFilter(QString)));
+ QObject::connect(this->groupedCheck, &QCheckBox::toggled, this,
+ &CMakeSetupDialog::setGroupedView);
+ QObject::connect(this->advancedCheck, &QCheckBox::toggled, this,
+ &CMakeSetupDialog::setAdvancedView);
+ QObject::connect(this->Search, &QLineEdit::textChanged, this,
+ &CMakeSetupDialog::setSearchFilter);
QObject::connect(this->CMakeThread->cmakeInstance(),
- SIGNAL(generatorChanged(QString)), this,
- SLOT(updateGeneratorLabel(QString)));
+ &QCMake::generatorChanged, this,
+ &CMakeSetupDialog::updateGeneratorLabel);
this->updateGeneratorLabel(QString());
QObject::connect(this->CacheValues->cacheModel(),
- SIGNAL(dataChanged(QModelIndex, QModelIndex)), this,
- SLOT(setCacheModified()));
+ &QCMakeCacheModel::dataChanged, this,
+ &CMakeSetupDialog::setCacheModified);
QObject::connect(this->CacheValues->selectionModel(),
- SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
- this, SLOT(selectionChanged()));
- QObject::connect(this->RemoveEntry, SIGNAL(clicked(bool)), this,
- SLOT(removeSelectedCacheEntries()));
- QObject::connect(this->AddEntry, SIGNAL(clicked(bool)), this,
- SLOT(addCacheEntry()));
-
- QObject::connect(this->WarnUninitializedAction, SIGNAL(triggered(bool)),
+ &QItemSelectionModel::selectionChanged, this,
+ &CMakeSetupDialog::selectionChanged);
+ QObject::connect(this->RemoveEntry, &QToolButton::clicked, this,
+ &CMakeSetupDialog::removeSelectedCacheEntries);
+ QObject::connect(this->AddEntry, &QToolButton::clicked, this,
+ &CMakeSetupDialog::addCacheEntry);
+
+ QObject::connect(this->Environment, &QToolButton::clicked, this,
+ &CMakeSetupDialog::editEnvironment);
+
+ QObject::connect(this->WarnUninitializedAction, &QAction::triggered,
this->CMakeThread->cmakeInstance(),
- SLOT(setWarnUninitializedMode(bool)));
+ &QCMake::setWarnUninitializedMode);
if (!this->SourceDirectory->text().isEmpty() ||
!this->BinaryDirectory->lineEdit()->text().isEmpty()) {
@@ -445,7 +458,8 @@ void CMakeSetupDialog::doInstallForCommandLine()
lab->setTextInteractionFlags(Qt::TextSelectableByMouse);
QDialogButtonBox* btns =
new QDialogButtonBox(QDialogButtonBox::Ok, Qt::Horizontal, &dialog);
- QObject::connect(btns, SIGNAL(accepted()), &dialog, SLOT(accept()));
+ QObject::connect(btns, &QDialogButtonBox::accepted, &dialog,
+ &QDialog::accept);
l->addWidget(btns);
dialog.exec();
}
@@ -602,7 +616,8 @@ void CMakeSetupDialog::doHelp()
lab->setWordWrap(true);
QDialogButtonBox* btns =
new QDialogButtonBox(QDialogButtonBox::Ok, Qt::Horizontal, &dialog);
- QObject::connect(btns, SIGNAL(accepted()), &dialog, SLOT(accept()));
+ QObject::connect(btns, &QDialogButtonBox::accepted, &dialog,
+ &QDialog::accept);
l->addWidget(lab);
l->addWidget(btns);
dialog.exec();
@@ -732,6 +747,7 @@ void CMakeSetupDialog::setEnabledState(bool enabled)
this->ConfigureAction->setEnabled(enabled);
this->AddEntry->setEnabled(enabled);
this->RemoveEntry->setEnabled(false); // let selection re-enable it
+ this->Environment->setEnabled(enabled);
}
bool CMakeSetupDialog::setupFirstConfigure()
@@ -891,7 +907,8 @@ void CMakeSetupDialog::doAbout()
lab->setWordWrap(true);
QDialogButtonBox* btns =
new QDialogButtonBox(QDialogButtonBox::Ok, Qt::Horizontal, &dialog);
- QObject::connect(btns, SIGNAL(accepted()), &dialog, SLOT(accept()));
+ QObject::connect(btns, &QDialogButtonBox::accepted, &dialog,
+ &QDialog::accept);
l->addWidget(btns);
dialog.exec();
}
@@ -1064,6 +1081,17 @@ void CMakeSetupDialog::enterState(CMakeSetupDialog::State s)
}
}
+void CMakeSetupDialog::editEnvironment()
+{
+ EnvironmentDialog dialog(this->CMakeThread->cmakeInstance()->environment(),
+ this);
+ if (dialog.exec() == QDialog::Accepted) {
+ QMetaObject::invokeMethod(
+ this->CMakeThread->cmakeInstance(), "setEnvironment",
+ Q_ARG(QProcessEnvironment, dialog.environment()));
+ }
+}
+
void CMakeSetupDialog::addCacheEntry()
{
QDialog dialog(this);
@@ -1074,8 +1102,10 @@ void CMakeSetupDialog::addCacheEntry()
new AddCacheEntry(&dialog, this->AddVariableNames, this->AddVariableTypes);
QDialogButtonBox* btns = new QDialogButtonBox(
QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, &dialog);
- QObject::connect(btns, SIGNAL(accepted()), &dialog, SLOT(accept()));
- QObject::connect(btns, SIGNAL(rejected()), &dialog, SLOT(reject()));
+ QObject::connect(btns, &QDialogButtonBox::accepted, &dialog,
+ &QDialog::accept);
+ QObject::connect(btns, &QDialogButtonBox::rejected, &dialog,
+ &QDialog::reject);
l->addWidget(w);
l->addStretch();
l->addWidget(btns);
@@ -1153,7 +1183,8 @@ void CMakeSetupDialog::showUserChanges()
l->addWidget(textedit);
QDialogButtonBox* btns =
new QDialogButtonBox(QDialogButtonBox::Close, Qt::Horizontal, &dialog);
- QObject::connect(btns, SIGNAL(rejected()), &dialog, SLOT(accept()));
+ QObject::connect(btns, &QDialogButtonBox::rejected, &dialog,
+ &QDialog::accept);
l->addWidget(btns);
QString command;
@@ -1207,15 +1238,23 @@ void CMakeSetupDialog::doOutputContextMenu(QPoint pt)
std::unique_ptr<QMenu> menu(this->Output->createStandardContextMenu());
menu->addSeparator();
- menu->addAction(tr("Find..."), this, SLOT(doOutputFindDialog()),
- QKeySequence::Find);
- menu->addAction(tr("Find Next"), this, SLOT(doOutputFindNext()),
- QKeySequence::FindNext);
- menu->addAction(tr("Find Previous"), this, SLOT(doOutputFindPrev()),
- QKeySequence::FindPrevious);
+ auto* a = menu->addAction(tr("Find..."));
+ QObject::connect(a, &QAction::triggered, this,
+ &CMakeSetupDialog::doOutputFindDialog);
+ a->setShortcut(QKeySequence::Find);
+ a = menu->addAction(tr("Find Next"));
+ QObject::connect(a, &QAction::triggered, this,
+ &CMakeSetupDialog::doOutputFindNext);
+ a->setShortcut(QKeySequence::FindNext);
+ a = menu->addAction(tr("Find Previous"));
+ QObject::connect(a, &QAction::triggered, this,
+ &CMakeSetupDialog::doOutputFindPrev);
+ a->setShortcut(QKeySequence::FindPrevious);
menu->addSeparator();
- menu->addAction(tr("Goto Next Error"), this, SLOT(doOutputErrorNext()),
- QKeySequence(Qt::Key_F8));
+ a = menu->addAction(tr("Goto Next Error"));
+ QObject::connect(a, &QAction::triggered, this,
+ &CMakeSetupDialog::doOutputErrorNext);
+ a->setShortcut(QKeySequence(Qt::Key_F8));
menu->exec(this->Output->mapToGlobal(pt));
}
diff --git a/Source/QtDialog/CMakeSetupDialog.h b/Source/QtDialog/CMakeSetupDialog.h
index eba0b1e..d752ef2 100644
--- a/Source/QtDialog/CMakeSetupDialog.h
+++ b/Source/QtDialog/CMakeSetupDialog.h
@@ -65,6 +65,7 @@ protected slots:
void setCacheModified();
void removeSelectedCacheEntries();
void selectionChanged();
+ void editEnvironment();
void addCacheEntry();
void startSearch();
void setDebugOutput(bool);
diff --git a/Source/QtDialog/CMakeSetupDialog.ui b/Source/QtDialog/CMakeSetupDialog.ui
index dc22a29..5feee91 100644
--- a/Source/QtDialog/CMakeSetupDialog.ui
+++ b/Source/QtDialog/CMakeSetupDialog.ui
@@ -11,7 +11,16 @@
</rect>
</property>
<layout class="QGridLayout">
- <property name="margin">
+ <property name="leftMargin">
+ <number>9</number>
+ </property>
+ <property name="topMargin">
+ <number>9</number>
+ </property>
+ <property name="rightMargin">
+ <number>9</number>
+ </property>
+ <property name="bottomMargin">
<number>9</number>
</property>
<property name="spacing">
@@ -19,7 +28,16 @@
</property>
<item row="0" column="0">
<layout class="QGridLayout">
- <property name="margin">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
<number>0</number>
</property>
<property name="spacing">
@@ -90,7 +108,16 @@
<property name="spacing">
<number>6</number>
</property>
- <property name="margin">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
<number>0</number>
</property>
<item>
@@ -98,7 +125,16 @@
<property name="spacing">
<number>6</number>
</property>
- <property name="margin">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
<number>0</number>
</property>
<item>
@@ -191,6 +227,13 @@
</property>
</widget>
</item>
+ <item>
+ <widget class="QPushButton" name="Environment">
+ <property name="text">
+ <string>E&amp;nvironment...</string>
+ </property>
+ </widget>
+ </item>
</layout>
</item>
<item>
@@ -224,7 +267,16 @@
<property name="spacing">
<number>6</number>
</property>
- <property name="margin">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
<number>0</number>
</property>
<item>
@@ -241,13 +293,13 @@
</property>
</widget>
</item>
- <item>
- <widget class="QPushButton" name="OpenProjectButton">
- <property name="text">
- <string>Open &amp;Project</string>
- </property>
- </widget>
- </item>
+ <item>
+ <widget class="QPushButton" name="OpenProjectButton">
+ <property name="text">
+ <string>Open &amp;Project</string>
+ </property>
+ </widget>
+ </item>
<item>
<widget class="QLabel" name="Generator">
<property name="text">
diff --git a/Source/QtDialog/EnvironmentDialog.cxx b/Source/QtDialog/EnvironmentDialog.cxx
new file mode 100644
index 0000000..846456c
--- /dev/null
+++ b/Source/QtDialog/EnvironmentDialog.cxx
@@ -0,0 +1,194 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "EnvironmentDialog.h"
+
+#include <QDialogButtonBox>
+#include <QGridLayout>
+#include <QItemSelectionModel>
+#include <QLabel>
+#include <QLineEdit>
+#include <QMessageBox>
+#include <QStandardItem>
+
+EnvironmentItemModel::EnvironmentItemModel(
+ const QProcessEnvironment& environment, QObject* parent)
+ : QStandardItemModel(parent)
+{
+ this->clear();
+ for (auto const& key : environment.keys()) {
+ auto value = environment.value(key);
+ this->appendVariable(key, value);
+ }
+}
+
+QProcessEnvironment EnvironmentItemModel::environment() const
+{
+ QProcessEnvironment env;
+ for (int i = 0; i < this->rowCount(); ++i) {
+ auto name = this->data(this->index(i, 0), Qt::DisplayRole).toString();
+ auto value = this->data(this->index(i, 1), Qt::DisplayRole).toString();
+ env.insert(name, value);
+ }
+ return env;
+}
+
+void EnvironmentItemModel::clear()
+{
+ this->QStandardItemModel::clear();
+
+ QStringList labels;
+ labels << tr("Name") << tr("Value");
+ this->setHorizontalHeaderLabels(labels);
+}
+
+QModelIndex EnvironmentItemModel::buddy(const QModelIndex& index) const
+{
+ if (index.column() == 0) {
+ return this->index(index.row(), index.column() + 1, index.parent());
+ }
+ return index;
+}
+
+void EnvironmentItemModel::appendVariable(const QString& key,
+ const QString& value)
+{
+ this->insertVariable(this->rowCount(), key, value);
+}
+
+void EnvironmentItemModel::insertVariable(int row, const QString& key,
+ const QString& value)
+{
+ for (int i = 0; i < this->rowCount(); ++i) {
+ if (this->data(this->index(i, 0), Qt::DisplayRole) == key) {
+ this->setData(this->index(i, 1), value, Qt::DisplayRole);
+ return;
+ }
+ }
+
+ auto* keyItem = new QStandardItem(key);
+ auto* valueItem = new QStandardItem(value);
+ this->insertRow(row, { keyItem, valueItem });
+}
+
+EnvironmentSearchFilter::EnvironmentSearchFilter(QObject* parent)
+ : QSortFilterProxyModel(parent)
+{
+}
+
+bool EnvironmentSearchFilter::filterAcceptsRow(int row,
+ const QModelIndex& parent) const
+{
+ auto* model = this->sourceModel();
+ auto key =
+ model->data(model->index(row, 0, parent), Qt::DisplayRole).toString();
+ return key.contains(this->filterRegExp());
+}
+
+EnvironmentDialog::EnvironmentDialog(const QProcessEnvironment& environment,
+ QWidget* parent)
+ : QDialog(parent)
+{
+ this->setupUi(this);
+
+ this->RemoveEntry->setEnabled(false);
+
+ this->m_model = new EnvironmentItemModel(environment, this);
+ this->m_filter = new EnvironmentSearchFilter(this);
+ this->m_filter->setSourceModel(this->m_model);
+ this->Environment->setModel(this->m_filter);
+
+ this->Environment->setUniformRowHeights(true);
+ this->Environment->setRootIsDecorated(false);
+ this->Environment->setSelectionMode(QAbstractItemView::ExtendedSelection);
+ this->Environment->setSelectionBehavior(QAbstractItemView::SelectRows);
+
+ QObject::connect(this->AddEntry, &QToolButton::clicked, this,
+ &EnvironmentDialog::addEntry);
+ QObject::connect(this->RemoveEntry, &QToolButton::clicked, this,
+ &EnvironmentDialog::removeSelectedEntries);
+ QObject::connect(this->Search, &QLineEdit::textChanged, this->m_filter,
+ &EnvironmentSearchFilter::setFilterFixedString);
+ QObject::connect(this->Environment->selectionModel(),
+ &QItemSelectionModel::selectionChanged, this,
+ &EnvironmentDialog::selectionChanged);
+}
+
+QProcessEnvironment EnvironmentDialog::environment() const
+{
+ return this->m_model->environment();
+}
+
+void EnvironmentDialog::addEntry()
+{
+ // Build the dialog manually because it's simple enough
+ QDialog dialog(this);
+ dialog.setWindowTitle("Add Environment Variable");
+
+ auto* layout = new QGridLayout;
+ dialog.setLayout(layout);
+
+ auto* nameLabel = new QLabel;
+ nameLabel->setText("Name:");
+ layout->addWidget(nameLabel, 0, 0);
+
+ auto* nameEdit = new QLineEdit;
+ nameEdit->setObjectName("name");
+ layout->addWidget(nameEdit, 0, 1);
+
+ auto* valueLabel = new QLabel;
+ valueLabel->setText("Value:");
+ layout->addWidget(valueLabel, 1, 0);
+
+ auto* valueEdit = new QLineEdit;
+ valueEdit->setObjectName("value");
+ layout->addWidget(valueEdit, 1, 1);
+
+ auto* buttons = new QDialogButtonBox;
+ buttons->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
+ QObject::connect(
+ buttons, &QDialogButtonBox::accepted, &dialog,
+ [this, &dialog, nameEdit]() {
+ auto text = nameEdit->text();
+ if (text.isEmpty()) {
+ QMessageBox::critical(&dialog, "Error", "Name must be non-empty.");
+ return;
+ }
+
+ auto* model = this->Environment->model();
+ for (int i = 0; i < model->rowCount(); ++i) {
+ if (model->data(model->index(i, 0), Qt::DisplayRole) == text) {
+ QMessageBox::critical(
+ &dialog, "Error",
+ tr("Environment variable \"%1\" already exists.").arg(text));
+ return;
+ }
+ }
+
+ dialog.accept();
+ });
+ QObject::connect(buttons, &QDialogButtonBox::rejected, &dialog,
+ &QDialog::reject);
+ layout->addWidget(buttons, 2, 0, 1, 2);
+
+ if (dialog.exec() == QDialog::Accepted) {
+ this->m_model->insertVariable(0, nameEdit->text(), valueEdit->text());
+ }
+}
+
+void EnvironmentDialog::removeSelectedEntries()
+{
+ QModelIndexList idxs = this->Environment->selectionModel()->selectedRows();
+ QList<QPersistentModelIndex> pidxs;
+ foreach (QModelIndex const& i, idxs) {
+ pidxs.append(i);
+ }
+ foreach (QPersistentModelIndex const& pi, pidxs) {
+ this->Environment->model()->removeRow(pi.row(), pi.parent());
+ }
+}
+
+void EnvironmentDialog::selectionChanged()
+{
+ auto selected = this->Environment->selectionModel()->selectedRows();
+ this->RemoveEntry->setEnabled(!selected.isEmpty());
+}
diff --git a/Source/QtDialog/EnvironmentDialog.h b/Source/QtDialog/EnvironmentDialog.h
new file mode 100644
index 0000000..6aae798
--- /dev/null
+++ b/Source/QtDialog/EnvironmentDialog.h
@@ -0,0 +1,59 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <QDialog>
+#include <QObject>
+#include <QProcessEnvironment>
+#include <QSortFilterProxyModel>
+#include <QStandardItemModel>
+
+#include "ui_EnvironmentDialog.h"
+
+class EnvironmentItemModel : public QStandardItemModel
+{
+ Q_OBJECT
+public:
+ EnvironmentItemModel(const QProcessEnvironment& environment,
+ QObject* parent = nullptr);
+
+ QProcessEnvironment environment() const;
+ void clear();
+
+ QModelIndex buddy(const QModelIndex& index) const override;
+
+public slots:
+ void appendVariable(const QString& key, const QString& value);
+ void insertVariable(int row, const QString& key, const QString& value);
+};
+
+class EnvironmentSearchFilter : public QSortFilterProxyModel
+{
+ Q_OBJECT
+public:
+ EnvironmentSearchFilter(QObject* parent = nullptr);
+
+protected:
+ bool filterAcceptsRow(int row, const QModelIndex& parent) const override;
+};
+
+class EnvironmentDialog
+ : public QDialog
+ , public Ui::EnvironmentDialog
+{
+ Q_OBJECT
+public:
+ EnvironmentDialog(const QProcessEnvironment& environment,
+ QWidget* parent = nullptr);
+
+ QProcessEnvironment environment() const;
+
+protected slots:
+ void addEntry();
+ void removeSelectedEntries();
+ void selectionChanged();
+
+private:
+ EnvironmentItemModel* m_model;
+ EnvironmentSearchFilter* m_filter;
+};
diff --git a/Source/QtDialog/EnvironmentDialog.ui b/Source/QtDialog/EnvironmentDialog.ui
new file mode 100644
index 0000000..dea7624
--- /dev/null
+++ b/Source/QtDialog/EnvironmentDialog.ui
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>EnvironmentDialog</class>
+ <widget class="QDialog" name="EnvironmentDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Environment Editor</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>S&amp;earch:</string>
+ </property>
+ <property name="buddy">
+ <cstring>Search</cstring>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="Search"/>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Minimum</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>12</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QToolButton" name="AddEntry">
+ <property name="text">
+ <string>&amp;Add Entry</string>
+ </property>
+ <property name="icon">
+ <iconset resource="CMakeSetup.qrc">
+ <normaloff>:/Icons/Plus16.png</normaloff>:/Icons/Plus16.png</iconset>
+ </property>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonTextBesideIcon</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="RemoveEntry">
+ <property name="text">
+ <string>&amp;Remove Entry</string>
+ </property>
+ <property name="icon">
+ <iconset resource="CMakeSetup.qrc">
+ <normaloff>:/Icons/Delete16.png</normaloff>:/Icons/Delete16.png</iconset>
+ </property>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonTextBesideIcon</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QTreeView" name="Environment"/>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources>
+ <include location="CMakeSetup.qrc"/>
+ </resources>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>EnvironmentDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>EnvironmentDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/Source/QtDialog/FirstConfigure.cxx b/Source/QtDialog/FirstConfigure.cxx
index 3c24b9b..918f137 100644
--- a/Source/QtDialog/FirstConfigure.cxx
+++ b/Source/QtDialog/FirstConfigure.cxx
@@ -47,17 +47,18 @@ StartCompilerSetup::StartCompilerSetup(QString defaultGeneratorPlatform,
this->CompilerSetupOptions[0]->setChecked(true);
- QObject::connect(this->CompilerSetupOptions[0], SIGNAL(toggled(bool)), this,
- SLOT(onSelectionChanged(bool)));
- QObject::connect(this->CompilerSetupOptions[1], SIGNAL(toggled(bool)), this,
- SLOT(onSelectionChanged(bool)));
- QObject::connect(this->CompilerSetupOptions[2], SIGNAL(toggled(bool)), this,
- SLOT(onSelectionChanged(bool)));
- QObject::connect(this->CompilerSetupOptions[3], SIGNAL(toggled(bool)), this,
- SLOT(onSelectionChanged(bool)));
- QObject::connect(this->GeneratorOptions,
- SIGNAL(currentIndexChanged(QString const&)), this,
- SLOT(onGeneratorChanged(QString const&)));
+ QObject::connect(this->CompilerSetupOptions[0], &QRadioButton::toggled, this,
+ &StartCompilerSetup::onSelectionChanged);
+ QObject::connect(this->CompilerSetupOptions[1], &QRadioButton::toggled, this,
+ &StartCompilerSetup::onSelectionChanged);
+ QObject::connect(this->CompilerSetupOptions[2], &QRadioButton::toggled, this,
+ &StartCompilerSetup::onSelectionChanged);
+ QObject::connect(this->CompilerSetupOptions[3], &QRadioButton::toggled, this,
+ &StartCompilerSetup::onSelectionChanged);
+ QObject::connect(
+ this->GeneratorOptions,
+ static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
+ this, &StartCompilerSetup::onGeneratorChanged);
}
QFrame* StartCompilerSetup::CreateToolsetWidgets()
@@ -186,8 +187,10 @@ void StartCompilerSetup::onSelectionChanged(bool on)
}
}
-void StartCompilerSetup::onGeneratorChanged(QString const& name)
+void StartCompilerSetup::onGeneratorChanged(int index)
{
+ QString name = this->GeneratorOptions->itemText(index);
+
// Display the generator platform for the generators supporting it
if (GeneratorsSupportingPlatform.contains(name)) {
@@ -458,9 +461,9 @@ FirstConfigure::FirstConfigure()
this->mStartCompilerSetupPage = new StartCompilerSetup(
env_generator_platform, env_generator_toolset, this);
this->setPage(Start, this->mStartCompilerSetupPage);
- QObject::connect(this->mStartCompilerSetupPage, SIGNAL(selectionChanged()),
- this, SLOT(restart()));
-
+ QObject::connect(this->mStartCompilerSetupPage,
+ &StartCompilerSetup::selectionChanged, this,
+ &FirstConfigure::restart);
this->mNativeCompilerSetupPage = new NativeCompilerSetup(this);
this->setPage(NativeSetup, this->mNativeCompilerSetupPage);
diff --git a/Source/QtDialog/FirstConfigure.h b/Source/QtDialog/FirstConfigure.h
index 4c757da..ca5f52e 100644
--- a/Source/QtDialog/FirstConfigure.h
+++ b/Source/QtDialog/FirstConfigure.h
@@ -49,7 +49,7 @@ signals:
protected slots:
void onSelectionChanged(bool);
- void onGeneratorChanged(QString const& name);
+ void onGeneratorChanged(int index);
protected:
QComboBox* GeneratorOptions;
diff --git a/Source/QtDialog/QCMake.cxx b/Source/QtDialog/QCMake.cxx
index 6090256..974c545 100644
--- a/Source/QtDialog/QCMake.cxx
+++ b/Source/QtDialog/QCMake.cxx
@@ -19,10 +19,12 @@
QCMake::QCMake(QObject* p)
: QObject(p)
+ , Environment(QProcessEnvironment::systemEnvironment())
{
this->WarnUninitializedMode = false;
qRegisterMetaType<QCMakeProperty>();
qRegisterMetaType<QCMakePropertyList>();
+ qRegisterMetaType<QProcessEnvironment>();
cmSystemTools::DisableRunCommandOutput();
cmSystemTools::SetRunCommandHideConsole(true);
@@ -151,34 +153,46 @@ void QCMake::setToolset(const QString& toolset)
}
}
+void QCMake::setEnvironment(const QProcessEnvironment& environment)
+{
+ this->Environment = environment;
+}
+
void QCMake::configure()
{
+ int err;
+ {
+ cmSystemTools::SaveRestoreEnvironment restoreEnv;
+ this->setUpEnvironment();
+
#ifdef Q_OS_WIN
- UINT lastErrorMode = SetErrorMode(0);
+ UINT lastErrorMode = SetErrorMode(0);
#endif
- this->CMakeInstance->SetHomeDirectory(
- this->SourceDirectory.toLocal8Bit().data());
- this->CMakeInstance->SetHomeOutputDirectory(
- this->BinaryDirectory.toLocal8Bit().data());
- this->CMakeInstance->SetGlobalGenerator(
- this->CMakeInstance->CreateGlobalGenerator(
- this->Generator.toLocal8Bit().data()));
- this->CMakeInstance->SetGeneratorPlatform(
- this->Platform.toLocal8Bit().data());
- this->CMakeInstance->SetGeneratorToolset(this->Toolset.toLocal8Bit().data());
- this->CMakeInstance->LoadCache();
- this->CMakeInstance->SetWarnUninitialized(this->WarnUninitializedMode);
- this->CMakeInstance->PreLoadCMakeFiles();
-
- InterruptFlag = 0;
- cmSystemTools::ResetErrorOccuredFlag();
-
- int err = this->CMakeInstance->Configure();
+ this->CMakeInstance->SetHomeDirectory(
+ this->SourceDirectory.toLocal8Bit().data());
+ this->CMakeInstance->SetHomeOutputDirectory(
+ this->BinaryDirectory.toLocal8Bit().data());
+ this->CMakeInstance->SetGlobalGenerator(
+ this->CMakeInstance->CreateGlobalGenerator(
+ this->Generator.toLocal8Bit().data()));
+ this->CMakeInstance->SetGeneratorPlatform(
+ this->Platform.toLocal8Bit().data());
+ this->CMakeInstance->SetGeneratorToolset(
+ this->Toolset.toLocal8Bit().data());
+ this->CMakeInstance->LoadCache();
+ this->CMakeInstance->SetWarnUninitialized(this->WarnUninitializedMode);
+ this->CMakeInstance->PreLoadCMakeFiles();
+
+ InterruptFlag = 0;
+ cmSystemTools::ResetErrorOccuredFlag();
+
+ err = this->CMakeInstance->Configure();
#ifdef Q_OS_WIN
- SetErrorMode(lastErrorMode);
+ SetErrorMode(lastErrorMode);
#endif
+ }
emit this->propertiesChanged(this->properties());
emit this->configureDone(err);
@@ -186,18 +200,24 @@ void QCMake::configure()
void QCMake::generate()
{
+ int err;
+ {
+ cmSystemTools::SaveRestoreEnvironment restoreEnv;
+ this->setUpEnvironment();
+
#ifdef Q_OS_WIN
- UINT lastErrorMode = SetErrorMode(0);
+ UINT lastErrorMode = SetErrorMode(0);
#endif
- InterruptFlag = 0;
- cmSystemTools::ResetErrorOccuredFlag();
+ InterruptFlag = 0;
+ cmSystemTools::ResetErrorOccuredFlag();
- int err = this->CMakeInstance->Generate();
+ err = this->CMakeInstance->Generate();
#ifdef Q_OS_WIN
- SetErrorMode(lastErrorMode);
+ SetErrorMode(lastErrorMode);
#endif
+ }
emit this->generateDone(err);
checkOpenPossible();
@@ -373,6 +393,18 @@ void QCMake::stderrCallback(std::string const& msg)
QCoreApplication::processEvents();
}
+void QCMake::setUpEnvironment() const
+{
+ auto env = QProcessEnvironment::systemEnvironment();
+ for (auto const& key : env.keys()) {
+ cmSystemTools::UnsetEnv(key.toLocal8Bit().data());
+ }
+
+ for (auto const& var : this->Environment.toStringList()) {
+ cmSystemTools::PutEnv(var.toLocal8Bit().data());
+ }
+}
+
QString QCMake::binaryDirectory() const
{
return this->BinaryDirectory;
@@ -388,6 +420,11 @@ QString QCMake::generator() const
return this->Generator;
}
+QProcessEnvironment QCMake::environment() const
+{
+ return this->Environment;
+}
+
std::vector<cmake::GeneratorInfo> const& QCMake::availableGenerators() const
{
return AvailableGenerators;
diff --git a/Source/QtDialog/QCMake.h b/Source/QtDialog/QCMake.h
index e87660b..f569951 100644
--- a/Source/QtDialog/QCMake.h
+++ b/Source/QtDialog/QCMake.h
@@ -18,6 +18,7 @@
#include <QList>
#include <QMetaType>
#include <QObject>
+#include <QProcessEnvironment>
#include <QString>
#include <QStringList>
#include <QVariant>
@@ -55,6 +56,7 @@ using QCMakePropertyList = QList<QCMakeProperty>;
// allow QVariant to be a property or list of properties
Q_DECLARE_METATYPE(QCMakeProperty)
Q_DECLARE_METATYPE(QCMakePropertyList)
+Q_DECLARE_METATYPE(QProcessEnvironment)
/// Qt API for CMake library.
/// Wrapper like class allows for easier integration with
@@ -78,6 +80,8 @@ public slots:
void setPlatform(const QString& platform);
/// set the desired generator to use
void setToolset(const QString& toolset);
+ /// set the configure and generate environment
+ void setEnvironment(const QProcessEnvironment& environment);
/// do the configure step
void configure();
/// generate the files
@@ -125,6 +129,8 @@ public:
QString sourceDirectory() const;
/// get the current generator
QString generator() const;
+ /// get the configure and generate environment
+ QProcessEnvironment environment() const;
/// get the available generators
std::vector<cmake::GeneratorInfo> const& availableGenerators() const;
/// get whether to do debug output
@@ -170,6 +176,7 @@ protected:
void messageCallback(std::string const& msg, const char* title);
void stdoutCallback(std::string const& msg);
void stderrCallback(std::string const& msg);
+ void setUpEnvironment() const;
bool WarnUninitializedMode;
QString SourceDirectory;
@@ -180,4 +187,5 @@ protected:
std::vector<cmake::GeneratorInfo> AvailableGenerators;
QString CMakeExecutable;
QAtomicInt InterruptFlag;
+ QProcessEnvironment Environment;
};
diff --git a/Source/QtDialog/QCMakeCacheView.cxx b/Source/QtDialog/QCMakeCacheView.cxx
index 3bf4409..4f4b218 100644
--- a/Source/QtDialog/QCMakeCacheView.cxx
+++ b/Source/QtDialog/QCMakeCacheView.cxx
@@ -576,15 +576,15 @@ QWidget* QCMakeCacheModelDelegate::createEditor(
if (type == QCMakeProperty::PATH) {
QCMakePathEditor* editor =
new QCMakePathEditor(p, var.data(Qt::DisplayRole).toString());
- QObject::connect(editor, SIGNAL(fileDialogExists(bool)), this,
- SLOT(setFileDialogFlag(bool)));
+ QObject::connect(editor, &QCMakePathEditor::fileDialogExists, this,
+ &QCMakeCacheModelDelegate::setFileDialogFlag);
return editor;
}
if (type == QCMakeProperty::FILEPATH) {
QCMakeFilePathEditor* editor =
new QCMakeFilePathEditor(p, var.data(Qt::DisplayRole).toString());
- QObject::connect(editor, SIGNAL(fileDialogExists(bool)), this,
- SLOT(setFileDialogFlag(bool)));
+ QObject::connect(editor, &QCMakePathEditor::fileDialogExists, this,
+ &QCMakeCacheModelDelegate::setFileDialogFlag);
return editor;
}
if (type == QCMakeProperty::STRING &&
diff --git a/Source/QtDialog/QCMakeWidgets.cxx b/Source/QtDialog/QCMakeWidgets.cxx
index d16ea58..1fc839f 100644
--- a/Source/QtDialog/QCMakeWidgets.cxx
+++ b/Source/QtDialog/QCMakeWidgets.cxx
@@ -17,8 +17,8 @@ QCMakeFileEditor::QCMakeFileEditor(QWidget* p, QString var)
this->ToolButton = new QToolButton(this);
this->ToolButton->setText("...");
this->ToolButton->setCursor(QCursor(Qt::ArrowCursor));
- QObject::connect(this->ToolButton, SIGNAL(clicked(bool)), this,
- SLOT(chooseFile()));
+ QObject::connect(this->ToolButton, &QToolButton::clicked, this,
+ &QCMakeFileEditor::chooseFile);
}
QCMakeFilePathEditor::QCMakeFilePathEditor(QWidget* p, const QString& var)
diff --git a/Source/QtDialog/WarningMessagesDialog.cxx b/Source/QtDialog/WarningMessagesDialog.cxx
index f608a84..1fcf2b1 100644
--- a/Source/QtDialog/WarningMessagesDialog.cxx
+++ b/Source/QtDialog/WarningMessagesDialog.cxx
@@ -26,18 +26,22 @@ void WarningMessagesDialog::setInitialValues()
void WarningMessagesDialog::setupSignals()
{
- QObject::connect(this->buttonBox, SIGNAL(accepted()), this,
- SLOT(doAccept()));
+ QObject::connect(this->buttonBox, &QDialogButtonBox::accepted, this,
+ &WarningMessagesDialog::doAccept);
- QObject::connect(this->suppressDeveloperWarnings, SIGNAL(stateChanged(int)),
- this, SLOT(doSuppressDeveloperWarningsChanged(int)));
- QObject::connect(this->suppressDeprecatedWarnings, SIGNAL(stateChanged(int)),
- this, SLOT(doSuppressDeprecatedWarningsChanged(int)));
+ QObject::connect(this->suppressDeveloperWarnings, &QCheckBox::stateChanged,
+ this,
+ &WarningMessagesDialog::doSuppressDeveloperWarningsChanged);
+ QObject::connect(
+ this->suppressDeprecatedWarnings, &QCheckBox::stateChanged, this,
+ &WarningMessagesDialog::doSuppressDeprecatedWarningsChanged);
- QObject::connect(this->developerWarningsAsErrors, SIGNAL(stateChanged(int)),
- this, SLOT(doDeveloperWarningsAsErrorsChanged(int)));
- QObject::connect(this->deprecatedWarningsAsErrors, SIGNAL(stateChanged(int)),
- this, SLOT(doDeprecatedWarningsAsErrorsChanged(int)));
+ QObject::connect(this->developerWarningsAsErrors, &QCheckBox::stateChanged,
+ this,
+ &WarningMessagesDialog::doDeveloperWarningsAsErrorsChanged);
+ QObject::connect(
+ this->deprecatedWarningsAsErrors, &QCheckBox::stateChanged, this,
+ &WarningMessagesDialog::doDeprecatedWarningsAsErrorsChanged);
}
void WarningMessagesDialog::doAccept()
diff --git a/Source/cmCMakeLanguageCommand.cxx b/Source/cmCMakeLanguageCommand.cxx
index eb9269f..9277c20 100644
--- a/Source/cmCMakeLanguageCommand.cxx
+++ b/Source/cmCMakeLanguageCommand.cxx
@@ -7,11 +7,14 @@
#include <cstddef>
#include <memory>
#include <string>
+#include <utility>
+#include <cm/optional>
#include <cm/string_view>
#include <cmext/string_view>
#include "cmExecutionStatus.h"
+#include "cmGlobalGenerator.h"
#include "cmListFileCache.h"
#include "cmMakefile.h"
#include "cmRange.h"
@@ -19,6 +22,14 @@
#include "cmSystemTools.h"
namespace {
+
+bool FatalError(cmExecutionStatus& status, std::string const& error)
+{
+ status.SetError(error);
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+}
+
std::array<cm::static_string_view, 12> InvalidCommands{
{ // clang-format off
"function"_s, "endfunction"_s,
@@ -28,110 +39,327 @@ std::array<cm::static_string_view, 12> InvalidCommands{
"foreach"_s, "endforeach"_s
} // clang-format on
};
-}
-bool cmCMakeLanguageCommand(std::vector<cmListFileArgument> const& args,
- cmExecutionStatus& status)
+std::array<cm::static_string_view, 1> InvalidDeferCommands{
+ {
+ // clang-format off
+ "return"_s,
+ } // clang-format on
+};
+
+struct Defer
+{
+ std::string Id;
+ std::string IdVar;
+ cmMakefile* Directory = nullptr;
+};
+
+bool cmCMakeLanguageCommandCALL(std::vector<cmListFileArgument> const& args,
+ std::string const& callCommand,
+ size_t startArg, cm::optional<Defer> defer,
+ cmExecutionStatus& status)
{
- if (args.empty()) {
- status.SetError("called with incorrect number of arguments");
- return false;
+ // ensure specified command is valid
+ // start/end flow control commands are not allowed
+ auto cmd = cmSystemTools::LowerCase(callCommand);
+ if (std::find(InvalidCommands.cbegin(), InvalidCommands.cend(), cmd) !=
+ InvalidCommands.cend()) {
+ return FatalError(status,
+ cmStrCat("invalid command specified: "_s, callCommand));
+ }
+ if (defer &&
+ std::find(InvalidDeferCommands.cbegin(), InvalidDeferCommands.cend(),
+ cmd) != InvalidDeferCommands.cend()) {
+ return FatalError(status,
+ cmStrCat("invalid command specified: "_s, callCommand));
}
cmMakefile& makefile = status.GetMakefile();
- cmListFileContext context = makefile.GetExecutionContext();
+ cmListFileContext context = makefile.GetBacktrace().Top();
- bool result = false;
+ cmListFileFunction func;
+ func.Name = callCommand;
+ func.Line = context.Line;
- std::vector<std::string> dispatchExpandedArgs;
- std::vector<cmListFileArgument> dispatchArgs;
- dispatchArgs.emplace_back(args[0]);
- makefile.ExpandArguments(dispatchArgs, dispatchExpandedArgs);
+ // The rest of the arguments are passed to the function call above
+ for (size_t i = startArg; i < args.size(); ++i) {
+ cmListFileArgument lfarg;
+ lfarg.Delim = args[i].Delim;
+ lfarg.Line = context.Line;
+ lfarg.Value = args[i].Value;
+ func.Arguments.emplace_back(lfarg);
+ }
- if (dispatchExpandedArgs.empty()) {
- status.SetError("called with incorrect number of arguments");
- return false;
+ if (defer) {
+ if (defer->Id.empty()) {
+ defer->Id = makefile.NewDeferId();
+ }
+ if (!defer->IdVar.empty()) {
+ makefile.AddDefinition(defer->IdVar, defer->Id);
+ }
+ cmMakefile* deferMakefile =
+ defer->Directory ? defer->Directory : &makefile;
+ if (!deferMakefile->DeferCall(defer->Id, context.FilePath, func)) {
+ return FatalError(
+ status,
+ cmStrCat("DEFER CALL may not be scheduled in directory:\n "_s,
+ deferMakefile->GetCurrentBinaryDirectory(),
+ "\nat this time."_s));
+ }
+ return true;
}
+ return makefile.ExecuteCommand(func, status);
+}
- if (dispatchExpandedArgs[0] == "CALL") {
- if ((args.size() == 1 && dispatchExpandedArgs.size() != 2) ||
- dispatchExpandedArgs.size() > 2) {
- status.SetError("called with incorrect number of arguments");
- return false;
+bool cmCMakeLanguageCommandDEFER(Defer const& defer,
+ std::vector<std::string> const& args,
+ size_t arg, cmExecutionStatus& status)
+{
+ cmMakefile* deferMakefile =
+ defer.Directory ? defer.Directory : &status.GetMakefile();
+ if (args[arg] == "CANCEL_CALL"_s) {
+ ++arg; // Consume CANCEL_CALL.
+ auto ids = cmMakeRange(args).advance(arg);
+ for (std::string const& id : ids) {
+ if (id[0] >= 'A' && id[0] <= 'Z') {
+ return FatalError(
+ status, cmStrCat("DEFER CANCEL_CALL unknown argument:\n "_s, id));
+ }
+ if (!deferMakefile->DeferCancelCall(id)) {
+ return FatalError(
+ status,
+ cmStrCat("DEFER CANCEL_CALL may not update directory:\n "_s,
+ deferMakefile->GetCurrentBinaryDirectory(),
+ "\nat this time."_s));
+ }
+ }
+ return true;
+ }
+ if (args[arg] == "GET_CALL_IDS"_s) {
+ ++arg; // Consume GET_CALL_IDS.
+ if (arg == args.size()) {
+ return FatalError(status, "DEFER GET_CALL_IDS missing output variable");
+ }
+ std::string const& var = args[arg++];
+ if (arg != args.size()) {
+ return FatalError(status, "DEFER GET_CALL_IDS given too many arguments");
+ }
+ cm::optional<std::string> ids = deferMakefile->DeferGetCallIds();
+ if (!ids) {
+ return FatalError(
+ status,
+ cmStrCat("DEFER GET_CALL_IDS may not access directory:\n "_s,
+ deferMakefile->GetCurrentBinaryDirectory(),
+ "\nat this time."_s));
+ }
+ status.GetMakefile().AddDefinition(var, *ids);
+ return true;
+ }
+ if (args[arg] == "GET_CALL"_s) {
+ ++arg; // Consume GET_CALL.
+ if (arg == args.size()) {
+ return FatalError(status, "DEFER GET_CALL missing id");
+ }
+ std::string const& id = args[arg++];
+ if (arg == args.size()) {
+ return FatalError(status, "DEFER GET_CALL missing output variable");
+ }
+ std::string const& var = args[arg++];
+ if (arg != args.size()) {
+ return FatalError(status, "DEFER GET_CALL given too many arguments");
+ }
+ if (id.empty()) {
+ return FatalError(status, "DEFER GET_CALL id may not be empty");
+ }
+ if (id[0] >= 'A' && id[0] <= 'Z') {
+ return FatalError(status,
+ cmStrCat("DEFER GET_CALL unknown argument:\n "_s, id));
+ }
+ cm::optional<std::string> call = deferMakefile->DeferGetCall(id);
+ if (!call) {
+ return FatalError(
+ status,
+ cmStrCat("DEFER GET_CALL may not access directory:\n "_s,
+ deferMakefile->GetCurrentBinaryDirectory(),
+ "\nat this time."_s));
}
+ status.GetMakefile().AddDefinition(var, *call);
+ return true;
+ }
+ return FatalError(status,
+ cmStrCat("DEFER operation unknown: "_s, args[arg]));
+}
- // First argument is the name of the function to call
- std::string callCommand;
- size_t startArg;
- if (dispatchExpandedArgs.size() == 1) {
- std::vector<std::string> functionExpandedArg;
- std::vector<cmListFileArgument> functionArg;
- functionArg.emplace_back(args[1]);
- makefile.ExpandArguments(functionArg, functionExpandedArg);
+bool cmCMakeLanguageCommandEVAL(std::vector<cmListFileArgument> const& args,
+ cmExecutionStatus& status)
+{
+ cmMakefile& makefile = status.GetMakefile();
+ cmListFileContext context = makefile.GetBacktrace().Top();
+ std::vector<std::string> expandedArgs;
+ makefile.ExpandArguments(args, expandedArgs);
- if (functionExpandedArg.size() != 1) {
- status.SetError("called with incorrect number of arguments");
- return false;
- }
+ if (expandedArgs.size() < 2) {
+ return FatalError(status, "called with incorrect number of arguments");
+ }
- callCommand = functionExpandedArg[0];
- startArg = 2;
- } else {
- callCommand = dispatchExpandedArgs[1];
- startArg = 1;
+ if (expandedArgs[1] != "CODE") {
+ auto code_iter =
+ std::find(expandedArgs.begin() + 2, expandedArgs.end(), "CODE");
+ if (code_iter == expandedArgs.end()) {
+ return FatalError(status, "called without CODE argument");
}
+ return FatalError(
+ status,
+ "called with unsupported arguments between EVAL and CODE arguments");
+ }
- // ensure specified command is valid
- // start/end flow control commands are not allowed
- auto cmd = cmSystemTools::LowerCase(callCommand);
- if (std::find(InvalidCommands.cbegin(), InvalidCommands.cend(), cmd) !=
- InvalidCommands.cend()) {
- status.SetError(cmStrCat("invalid command specified: "_s, callCommand));
- return false;
- }
+ const std::string code =
+ cmJoin(cmMakeRange(expandedArgs.begin() + 2, expandedArgs.end()), " ");
+ return makefile.ReadListFileAsString(
+ code, cmStrCat(context.FilePath, ":", context.Line, ":EVAL"));
+}
+}
- cmListFileFunction func;
- func.Name = callCommand;
- func.Line = context.Line;
+bool cmCMakeLanguageCommand(std::vector<cmListFileArgument> const& args,
+ cmExecutionStatus& status)
+{
+ std::vector<std::string> expArgs;
+ size_t rawArg = 0;
+ size_t expArg = 0;
- // The rest of the arguments are passed to the function call above
- for (size_t i = startArg; i < args.size(); ++i) {
- cmListFileArgument lfarg;
- lfarg.Delim = args[i].Delim;
- lfarg.Line = context.Line;
- lfarg.Value = args[i].Value;
- func.Arguments.emplace_back(lfarg);
+ // Helper to consume and expand one raw argument at a time.
+ auto moreArgs = [&]() -> bool {
+ while (expArg >= expArgs.size()) {
+ if (rawArg >= args.size()) {
+ return false;
+ }
+ std::vector<cmListFileArgument> tmpArg;
+ tmpArg.emplace_back(args[rawArg++]);
+ status.GetMakefile().ExpandArguments(tmpArg, expArgs);
}
+ return true;
+ };
+ auto finishArgs = [&]() {
+ std::vector<cmListFileArgument> tmpArgs(args.begin() + rawArg, args.end());
+ status.GetMakefile().ExpandArguments(tmpArgs, expArgs);
+ rawArg = args.size();
+ };
- result = makefile.ExecuteCommand(func, status);
- } else if (dispatchExpandedArgs[0] == "EVAL") {
- std::vector<std::string> expandedArgs;
- makefile.ExpandArguments(args, expandedArgs);
+ if (!moreArgs()) {
+ return FatalError(status, "called with incorrect number of arguments");
+ }
+
+ cm::optional<Defer> maybeDefer;
+ if (expArgs[expArg] == "DEFER"_s) {
+ ++expArg; // Consume "DEFER".
- if (expandedArgs.size() < 2) {
- status.SetError("called with incorrect number of arguments");
- return false;
+ if (!moreArgs()) {
+ return FatalError(status, "DEFER requires at least one argument");
}
- if (expandedArgs[1] != "CODE") {
- auto code_iter =
- std::find(expandedArgs.begin() + 2, expandedArgs.end(), "CODE");
- if (code_iter == expandedArgs.end()) {
- status.SetError("called without CODE argument");
+ Defer defer;
+
+ // Process optional arguments.
+ while (moreArgs()) {
+ if (expArgs[expArg] == "CALL"_s) {
+ break;
+ }
+ if (expArgs[expArg] == "CANCEL_CALL"_s ||
+ expArgs[expArg] == "GET_CALL_IDS"_s ||
+ expArgs[expArg] == "GET_CALL"_s) {
+ if (!defer.Id.empty() || !defer.IdVar.empty()) {
+ return FatalError(status,
+ cmStrCat("DEFER "_s, expArgs[expArg],
+ " does not accept ID or ID_VAR."_s));
+ }
+ finishArgs();
+ return cmCMakeLanguageCommandDEFER(defer, expArgs, expArg, status);
+ }
+ if (expArgs[expArg] == "DIRECTORY"_s) {
+ ++expArg; // Consume "DIRECTORY".
+ if (defer.Directory) {
+ return FatalError(status,
+ "DEFER given multiple DIRECTORY arguments");
+ }
+ if (!moreArgs()) {
+ return FatalError(status, "DEFER DIRECTORY missing value");
+ }
+ std::string dir = expArgs[expArg++];
+ if (dir.empty()) {
+ return FatalError(status, "DEFER DIRECTORY may not be empty");
+ }
+ dir = cmSystemTools::CollapseFullPath(
+ dir, status.GetMakefile().GetCurrentSourceDirectory());
+ defer.Directory =
+ status.GetMakefile().GetGlobalGenerator()->FindMakefile(dir);
+ if (!defer.Directory) {
+ return FatalError(status,
+ cmStrCat("DEFER DIRECTORY:\n "_s, dir,
+ "\nis not known. "_s,
+ "It may not have been processed yet."_s));
+ }
+ } else if (expArgs[expArg] == "ID"_s) {
+ ++expArg; // Consume "ID".
+ if (!defer.Id.empty()) {
+ return FatalError(status, "DEFER given multiple ID arguments");
+ }
+ if (!moreArgs()) {
+ return FatalError(status, "DEFER ID missing value");
+ }
+ defer.Id = expArgs[expArg++];
+ if (defer.Id.empty()) {
+ return FatalError(status, "DEFER ID may not be empty");
+ }
+ if (defer.Id[0] >= 'A' && defer.Id[0] <= 'Z') {
+ return FatalError(status, "DEFER ID may not start in A-Z.");
+ }
+ } else if (expArgs[expArg] == "ID_VAR"_s) {
+ ++expArg; // Consume "ID_VAR".
+ if (!defer.IdVar.empty()) {
+ return FatalError(status, "DEFER given multiple ID_VAR arguments");
+ }
+ if (!moreArgs()) {
+ return FatalError(status, "DEFER ID_VAR missing variable name");
+ }
+ defer.IdVar = expArgs[expArg++];
+ if (defer.IdVar.empty()) {
+ return FatalError(status, "DEFER ID_VAR may not be empty");
+ }
} else {
- status.SetError(
- "called with unsupported arguments between EVAL and CODE arguments");
+ return FatalError(
+ status, cmStrCat("DEFER unknown option:\n "_s, expArgs[expArg]));
}
- return false;
}
- const std::string code =
- cmJoin(cmMakeRange(expandedArgs.begin() + 2, expandedArgs.end()), " ");
- result = makefile.ReadListFileAsString(
- code, cmStrCat(context.FilePath, ":", context.Line, ":EVAL"));
- } else {
- status.SetError("called with unknown meta-operation");
+ if (!(moreArgs() && expArgs[expArg] == "CALL"_s)) {
+ return FatalError(status, "DEFER must be followed by a CALL argument");
+ }
+
+ maybeDefer = std::move(defer);
+ }
+
+ if (expArgs[expArg] == "CALL") {
+ ++expArg; // Consume "CALL".
+
+ // CALL requires a command name.
+ if (!moreArgs()) {
+ return FatalError(status, "CALL missing command name");
+ }
+ std::string const& callCommand = expArgs[expArg++];
+
+ // CALL accepts no further expanded arguments.
+ if (expArg != expArgs.size()) {
+ return FatalError(status, "CALL command's arguments must be literal");
+ }
+
+ // Run the CALL.
+ return cmCMakeLanguageCommandCALL(args, callCommand, rawArg,
+ std::move(maybeDefer), status);
+ }
+
+ if (expArgs[expArg] == "EVAL") {
+ return cmCMakeLanguageCommandEVAL(args, status);
}
- return result;
+ return FatalError(status, "called with unknown meta-operation");
}
diff --git a/Source/cmCommandArgumentParserHelper.cxx b/Source/cmCommandArgumentParserHelper.cxx
index e3d014e..d4f5022 100644
--- a/Source/cmCommandArgumentParserHelper.cxx
+++ b/Source/cmCommandArgumentParserHelper.cxx
@@ -8,8 +8,11 @@
#include <utility>
#include <cm/memory>
+#include <cm/optional>
+#include <cmext/string_view>
#include "cmCommandArgumentLexer.h"
+#include "cmListFileCache.h"
#include "cmMakefile.h"
#include "cmProperty.h"
#include "cmState.h"
@@ -91,7 +94,14 @@ const char* cmCommandArgumentParserHelper::ExpandVariable(const char* var)
return nullptr;
}
if (this->FileLine >= 0 && strcmp(var, "CMAKE_CURRENT_LIST_LINE") == 0) {
- return this->AddString(std::to_string(this->FileLine));
+ std::string line;
+ cmListFileContext const& top = this->Makefile->GetBacktrace().Top();
+ if (top.DeferId) {
+ line = cmStrCat("DEFERRED:"_s, *top.DeferId);
+ } else {
+ line = std::to_string(this->FileLine);
+ }
+ return this->AddString(line);
}
cmProp value = this->Makefile->GetDefinition(var);
if (!value) {
diff --git a/Source/cmConditionEvaluator.cxx b/Source/cmConditionEvaluator.cxx
index 7ada8d8..14f10bd74 100644
--- a/Source/cmConditionEvaluator.cxx
+++ b/Source/cmConditionEvaluator.cxx
@@ -56,10 +56,8 @@ static std::string const keyVERSION_LESS = "VERSION_LESS";
static std::string const keyVERSION_LESS_EQUAL = "VERSION_LESS_EQUAL";
cmConditionEvaluator::cmConditionEvaluator(cmMakefile& makefile,
- cmListFileContext context,
cmListFileBacktrace bt)
: Makefile(makefile)
- , ExecutionContext(std::move(context))
, Backtrace(std::move(bt))
, Policy12Status(makefile.GetPolicyStatus(cmPolicies::CMP0012))
, Policy54Status(makefile.GetPolicyStatus(cmPolicies::CMP0054))
@@ -147,8 +145,7 @@ cmProp cmConditionEvaluator::GetDefinitionIfUnquoted(
if (def && argument.WasQuoted() &&
this->Policy54Status == cmPolicies::WARN) {
- if (!this->Makefile.HasCMP0054AlreadyBeenReported(
- this->ExecutionContext)) {
+ if (!this->Makefile.HasCMP0054AlreadyBeenReported(this->Backtrace.Top())) {
std::ostringstream e;
e << (cmPolicies::GetPolicyWarning(cmPolicies::CMP0054)) << "\n";
e << "Quoted variables like \"" << argument.GetValue()
@@ -191,8 +188,7 @@ bool cmConditionEvaluator::IsKeyword(std::string const& keyword,
if (isKeyword && argument.WasQuoted() &&
this->Policy54Status == cmPolicies::WARN) {
- if (!this->Makefile.HasCMP0054AlreadyBeenReported(
- this->ExecutionContext)) {
+ if (!this->Makefile.HasCMP0054AlreadyBeenReported(this->Backtrace.Top())) {
std::ostringstream e;
e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0054) << "\n";
e << "Quoted keywords like \"" << argument.GetValue()
diff --git a/Source/cmConditionEvaluator.h b/Source/cmConditionEvaluator.h
index a4cedff..cf00ede 100644
--- a/Source/cmConditionEvaluator.h
+++ b/Source/cmConditionEvaluator.h
@@ -21,8 +21,7 @@ class cmConditionEvaluator
public:
using cmArgumentList = std::list<cmExpandedCommandArgument>;
- cmConditionEvaluator(cmMakefile& makefile, cmListFileContext context,
- cmListFileBacktrace bt);
+ cmConditionEvaluator(cmMakefile& makefile, cmListFileBacktrace bt);
// this is a shared function for both If and Else to determine if the
// arguments were valid, and if so, was the response true. If there is
@@ -79,7 +78,6 @@ private:
MessageType& status);
cmMakefile& Makefile;
- cmListFileContext ExecutionContext;
cmListFileBacktrace Backtrace;
cmPolicies::PolicyStatus Policy12Status;
cmPolicies::PolicyStatus Policy54Status;
diff --git a/Source/cmExtraSublimeTextGenerator.cxx b/Source/cmExtraSublimeTextGenerator.cxx
index 3e265a0..1c7e4b1 100644
--- a/Source/cmExtraSublimeTextGenerator.cxx
+++ b/Source/cmExtraSublimeTextGenerator.cxx
@@ -446,13 +446,13 @@ bool cmExtraSublimeTextGenerator::Open(const std::string& bindir,
const std::string& projectName,
bool dryRun)
{
- const char* sublExecutable =
+ cmProp sublExecutable =
this->GlobalGenerator->GetCMakeInstance()->GetCacheDefinition(
"CMAKE_SUBLIMETEXT_EXECUTABLE");
if (!sublExecutable) {
return false;
}
- if (cmIsNOTFOUND(sublExecutable)) {
+ if (cmIsNOTFOUND(*sublExecutable)) {
return false;
}
@@ -462,5 +462,5 @@ bool cmExtraSublimeTextGenerator::Open(const std::string& bindir,
}
return cmSystemTools::RunSingleCommand(
- { sublExecutable, "--project", filename });
+ { *sublExecutable, "--project", filename });
}
diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx
index 51137b3..c988b59 100644
--- a/Source/cmFindPackageCommand.cxx
+++ b/Source/cmFindPackageCommand.cxx
@@ -426,7 +426,7 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
// fill various parts of version specification
if (!this->VersionComplete.empty()) {
if (!versionRegex.find(this->VersionComplete)) {
- this->SetError("called with invalid version specification");
+ this->SetError("called with invalid version specification.");
return false;
}
@@ -440,6 +440,19 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
}
}
+ if (!this->VersionRange.empty()) {
+ // version range must not be empty
+ if ((this->VersionRangeMax == VERSION_ENDPOINT_INCLUDED &&
+ cmSystemTools::VersionCompareGreater(this->Version,
+ this->VersionMax)) ||
+ (this->VersionRangeMax == VERSION_ENDPOINT_EXCLUDED &&
+ cmSystemTools::VersionCompareGreaterEq(this->Version,
+ this->VersionMax))) {
+ this->SetError("specified version range is empty.");
+ return false;
+ }
+ }
+
if (this->VersionExact && !this->VersionRange.empty()) {
this->SetError("EXACT cannot be specified with a version range.");
return false;
@@ -1971,6 +1984,9 @@ cmFileListGeneratorBase* cmFileListGeneratorBase::SetNext(
bool cmFileListGeneratorBase::Consider(std::string const& fullPath,
cmFileList& listing)
{
+ if (!cmSystemTools::FileIsDirectory(fullPath)) {
+ return false;
+ }
if (this->Next) {
return this->Next->Search(fullPath + "/", listing);
}
@@ -2225,10 +2241,8 @@ private:
// Look for directories among the matches.
for (std::string const& f : files) {
- if (cmSystemTools::FileIsDirectory(f)) {
- if (this->Consider(f, lister)) {
- return true;
- }
+ if (this->Consider(f, lister)) {
+ return true;
}
}
return false;
diff --git a/Source/cmFunctionCommand.cxx b/Source/cmFunctionCommand.cxx
index b6f58bd..46bd057 100644
--- a/Source/cmFunctionCommand.cxx
+++ b/Source/cmFunctionCommand.cxx
@@ -147,8 +147,7 @@ bool cmFunctionFunctionBlocker::ArgumentsMatch(cmListFileFunction const& lff,
cmMakefile& mf) const
{
std::vector<std::string> expandedArguments;
- mf.ExpandArguments(lff.Arguments, expandedArguments,
- this->GetStartingContext().FilePath.c_str());
+ mf.ExpandArguments(lff.Arguments, expandedArguments);
return expandedArguments.empty() ||
expandedArguments.front() == this->Args.front();
}
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 8589ab1..859fa6a 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -516,9 +516,8 @@ std::string cmGeneratorTarget::GetFilePrefix(
const std::string& config, cmStateEnums::ArtifactType artifact) const
{
if (this->IsImported()) {
- const char* prefix = this->GetFilePrefixInternal(config, artifact);
-
- return prefix ? prefix : std::string();
+ cmProp prefix = this->GetFilePrefixInternal(config, artifact);
+ return prefix ? *prefix : std::string();
}
std::string prefix;
@@ -531,9 +530,8 @@ std::string cmGeneratorTarget::GetFileSuffix(
const std::string& config, cmStateEnums::ArtifactType artifact) const
{
if (this->IsImported()) {
- const char* suffix = this->GetFileSuffixInternal(config, artifact);
-
- return suffix ? suffix : std::string();
+ cmProp suffix = this->GetFileSuffixInternal(config, artifact);
+ return suffix ? *suffix : std::string();
}
std::string prefix;
@@ -587,7 +585,7 @@ std::string cmGeneratorTarget::GetFrameworkMultiConfigPostfix(
return postfix ? *postfix : std::string();
}
-const char* cmGeneratorTarget::GetFilePrefixInternal(
+cmProp cmGeneratorTarget::GetFilePrefixInternal(
std::string const& config, cmStateEnums::ArtifactType artifact,
const std::string& language) const
{
@@ -623,8 +621,8 @@ const char* cmGeneratorTarget::GetFilePrefixInternal(
if (!targetPrefix) {
const char* prefixVar = this->Target->GetPrefixVariableInternal(artifact);
- if (!language.empty() && prefixVar && *prefixVar) {
- std::string langPrefix = prefixVar + std::string("_") + language;
+ if (!language.empty() && cmNonempty(prefixVar)) {
+ std::string langPrefix = cmStrCat(prefixVar, "_", language);
targetPrefix = this->Makefile->GetDefinition(langPrefix);
}
@@ -635,9 +633,10 @@ const char* cmGeneratorTarget::GetFilePrefixInternal(
}
}
- return targetPrefix ? targetPrefix->c_str() : nullptr;
+ return targetPrefix;
}
-const char* cmGeneratorTarget::GetFileSuffixInternal(
+
+cmProp cmGeneratorTarget::GetFileSuffixInternal(
std::string const& config, cmStateEnums::ArtifactType artifact,
const std::string& language) const
{
@@ -673,8 +672,8 @@ const char* cmGeneratorTarget::GetFileSuffixInternal(
if (!targetSuffix) {
const char* suffixVar = this->Target->GetSuffixVariableInternal(artifact);
- if (!language.empty() && suffixVar && *suffixVar) {
- std::string langSuffix = suffixVar + std::string("_") + language;
+ if (!language.empty() && cmNonempty(suffixVar)) {
+ std::string langSuffix = cmStrCat(suffixVar, "_", language);
targetSuffix = this->Makefile->GetDefinition(langSuffix);
}
@@ -685,7 +684,7 @@ const char* cmGeneratorTarget::GetFileSuffixInternal(
}
}
- return targetSuffix ? targetSuffix->c_str() : nullptr;
+ return targetSuffix;
}
void cmGeneratorTarget::ClearSourcesCache()
@@ -1195,8 +1194,8 @@ bool cmGeneratorTarget::IsSystemIncludeDirectory(
config_upper = cmSystemTools::UpperCase(config);
}
- using IncludeCacheType = std::map<std::string, std::vector<std::string>>;
- auto iter = this->SystemIncludesCache.find(config_upper);
+ std::string key = cmStrCat(config_upper, "/", language);
+ auto iter = this->SystemIncludesCache.find(key);
if (iter == this->SystemIncludesCache.end()) {
cmGeneratorExpressionDAGChecker dagChecker(
@@ -1224,8 +1223,7 @@ bool cmGeneratorTarget::IsSystemIncludeDirectory(
std::sort(result.begin(), result.end());
result.erase(std::unique(result.begin(), result.end()), result.end());
- IncludeCacheType::value_type entry(config_upper, result);
- iter = this->SystemIncludesCache.insert(entry).first;
+ iter = this->SystemIncludesCache.emplace(key, result).first;
}
return std::binary_search(iter->second.begin(), iter->second.end(), dir);
@@ -1248,8 +1246,7 @@ bool cmGeneratorTarget::MaybeHaveInterfaceProperty(
bool& maybeInterfaceProp = i->second;
// If this target itself has a non-empty property value, we are done.
- cmProp p = this->GetProperty(prop);
- maybeInterfaceProp = cmNonempty(p);
+ maybeInterfaceProp = cmNonempty(this->GetProperty(prop));
// Otherwise, recurse to interface dependencies.
if (!maybeInterfaceProp) {
@@ -4943,8 +4940,8 @@ void cmGeneratorTarget::GetFullNameInternal(
// retrieve prefix and suffix
std::string ll = this->GetLinkerLanguage(config);
- const char* targetPrefix = this->GetFilePrefixInternal(config, artifact, ll);
- const char* targetSuffix = this->GetFileSuffixInternal(config, artifact, ll);
+ cmProp targetPrefix = this->GetFilePrefixInternal(config, artifact, ll);
+ cmProp targetSuffix = this->GetFileSuffixInternal(config, artifact, ll);
// The implib option is only allowed for shared libraries, module
// libraries, and executables.
@@ -4962,18 +4959,18 @@ void cmGeneratorTarget::GetFullNameInternal(
if (this->IsFrameworkOnApple()) {
fw_prefix =
cmStrCat(this->GetFrameworkDirectory(config, ContentLevel), '/');
- targetPrefix = fw_prefix.c_str();
+ targetPrefix = &fw_prefix;
targetSuffix = nullptr;
}
if (this->IsCFBundleOnApple()) {
fw_prefix = cmStrCat(this->GetCFBundleDirectory(config, FullLevel), '/');
- targetPrefix = fw_prefix.c_str();
+ targetPrefix = &fw_prefix;
targetSuffix = nullptr;
}
// Begin the final name with the prefix.
- outPrefix = targetPrefix ? targetPrefix : "";
+ outPrefix = targetPrefix ? *targetPrefix : "";
// Append the target name or property-specified name.
outBase += this->GetOutputName(config, artifact);
@@ -4984,7 +4981,7 @@ void cmGeneratorTarget::GetFullNameInternal(
// EXECUTABLE_SUFFIX attribute.
if (this->IsFrameworkOnApple() &&
GetGlobalGenerator()->GetName() == "Xcode") {
- targetSuffix = configPostfix.c_str();
+ targetSuffix = &configPostfix;
} else {
outBase += configPostfix;
}
@@ -5000,7 +4997,7 @@ void cmGeneratorTarget::GetFullNameInternal(
}
// Append the suffix.
- outSuffix = targetSuffix ? targetSuffix : "";
+ outSuffix = targetSuffix ? *targetSuffix : "";
}
std::string cmGeneratorTarget::GetLinkerLanguage(
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index 8e0def7..e5fa892 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -849,6 +849,8 @@ private:
mutable std::set<std::string> VisitedConfigsForObjects;
mutable std::map<cmSourceFile const*, std::string> Objects;
std::set<cmSourceFile const*> ExplicitObjectName;
+
+ // "config/language" is the key
mutable std::map<std::string, std::vector<std::string>> SystemIncludesCache;
mutable std::string ExportMacro;
@@ -861,12 +863,12 @@ private:
bool NeedImportLibraryName(std::string const& config) const;
- const char* GetFilePrefixInternal(std::string const& config,
- cmStateEnums::ArtifactType artifact,
- const std::string& language = "") const;
- const char* GetFileSuffixInternal(std::string const& config,
- cmStateEnums::ArtifactType artifact,
- const std::string& language = "") const;
+ cmProp GetFilePrefixInternal(std::string const& config,
+ cmStateEnums::ArtifactType artifact,
+ const std::string& language = "") const;
+ cmProp GetFileSuffixInternal(std::string const& config,
+ cmStateEnums::ArtifactType artifact,
+ const std::string& language = "") const;
std::string GetFullNameInternal(const std::string& config,
cmStateEnums::ArtifactType artifact) const;
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index 86b01bc..1197db6 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -15,6 +15,7 @@
#include <cm/memory>
#include <cmext/algorithm>
+#include <cmext/string_view>
#include "cmsys/Directory.hxx"
#include "cmsys/FStream.hxx"
@@ -197,12 +198,12 @@ std::string cmGlobalGenerator::SelectMakeProgram(
{
std::string makeProgram = inMakeProgram;
if (cmIsOff(makeProgram)) {
- const char* makeProgramCSTR =
+ cmProp makeProgramCSTR =
this->CMakeInstance->GetCacheDefinition("CMAKE_MAKE_PROGRAM");
if (cmIsOff(makeProgramCSTR)) {
makeProgram = makeDefault;
} else {
- makeProgram = makeProgramCSTR;
+ makeProgram = *makeProgramCSTR;
}
if (cmIsOff(makeProgram) && !makeProgram.empty()) {
makeProgram = "CMAKE_MAKE_PROGRAM-NOTFOUND";
@@ -1211,6 +1212,7 @@ void cmGlobalGenerator::Configure()
{
this->FirstTimeProgress = 0.0f;
this->ClearGeneratorMembers();
+ this->NextDeferId = 0;
cmStateSnapshot snapshot = this->CMakeInstance->GetCurrentSnapshot();
@@ -2153,10 +2155,11 @@ void cmGlobalGenerator::EnableLanguagesFromGenerator(cmGlobalGenerator* gen,
{
this->SetConfiguredFilesPath(gen);
this->TryCompileOuterMakefile = mf;
- const char* make =
+ cmProp make =
gen->GetCMakeInstance()->GetCacheDefinition("CMAKE_MAKE_PROGRAM");
- this->GetCMakeInstance()->AddCacheEntry(
- "CMAKE_MAKE_PROGRAM", make, "make program", cmStateEnums::FILEPATH);
+ this->GetCMakeInstance()->AddCacheEntry("CMAKE_MAKE_PROGRAM", cmToCStr(make),
+ "make program",
+ cmStateEnums::FILEPATH);
// copy the enabled languages
this->GetCMakeInstance()->GetState()->SetEnabledLanguages(
gen->GetCMakeInstance()->GetState()->GetEnabledLanguages());
@@ -3255,6 +3258,11 @@ const std::string& cmGlobalGenerator::GetRealPath(const std::string& dir)
return i->second;
}
+std::string cmGlobalGenerator::NewDeferId()
+{
+ return cmStrCat("__"_s, std::to_string(this->NextDeferId++));
+}
+
void cmGlobalGenerator::ProcessEvaluationFiles()
{
std::vector<std::string> generatedFiles;
diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h
index 478028e..b532a43 100644
--- a/Source/cmGlobalGenerator.h
+++ b/Source/cmGlobalGenerator.h
@@ -508,6 +508,8 @@ public:
std::string const& GetRealPath(std::string const& dir);
+ std::string NewDeferId();
+
protected:
// for a project collect all its targets by following depend
// information, and also collect all the targets
@@ -633,6 +635,9 @@ private:
std::map<std::string, int> LanguageToLinkerPreference;
std::map<std::string, std::string> LanguageToOriginalSharedLibFlags;
+ // Deferral id generation.
+ size_t NextDeferId = 0;
+
// Record hashes for rules and outputs.
struct RuleHash
{
diff --git a/Source/cmGlobalGhsMultiGenerator.cxx b/Source/cmGlobalGhsMultiGenerator.cxx
index cbaf0ab..c08c9cf 100644
--- a/Source/cmGlobalGhsMultiGenerator.cxx
+++ b/Source/cmGlobalGhsMultiGenerator.cxx
@@ -3,7 +3,6 @@
#include "cmGlobalGhsMultiGenerator.h"
#include <algorithm>
-#include <cstring>
#include <map>
#include <ostream>
#include <utility>
@@ -335,23 +334,23 @@ void cmGlobalGhsMultiGenerator::WriteTopLevelProject(std::ostream& fout,
fout << "# Top Level Project File\n";
// Specify BSP option if supplied by user
- const char* bspName =
+ cmProp bspName =
this->GetCMakeInstance()->GetCacheDefinition("GHS_BSP_NAME");
if (!cmIsOff(bspName)) {
- fout << " -bsp " << bspName << '\n';
+ fout << " -bsp " << *bspName << '\n';
}
// Specify OS DIR if supplied by user
// -- not all platforms require this entry in the project file
if (!cmIsOff(this->OsDir)) {
- const char* osDirOption =
+ cmProp osDirOption =
this->GetCMakeInstance()->GetCacheDefinition("GHS_OS_DIR_OPTION");
std::replace(this->OsDir.begin(), this->OsDir.end(), '\\', '/');
fout << " ";
if (cmIsOff(osDirOption)) {
fout << "";
} else {
- fout << osDirOption;
+ fout << *osDirOption;
}
fout << "\"" << this->OsDir << "\"\n";
}
@@ -565,9 +564,9 @@ cmGlobalGhsMultiGenerator::GenerateBuildCommand(
{
GeneratedMakeCommand makeCommand = {};
std::string gbuild;
- if (const char* gbuildCached =
+ if (cmProp gbuildCached =
this->CMakeInstance->GetCacheDefinition("CMAKE_MAKE_PROGRAM")) {
- gbuild = gbuildCached;
+ gbuild = *gbuildCached;
}
makeCommand.Add(this->SelectMakeProgram(makeProgram, gbuild));
@@ -618,11 +617,10 @@ void cmGlobalGhsMultiGenerator::WriteMacros(std::ostream& fout,
cmLocalGenerator* root)
{
fout << "macro PROJ_NAME=" << root->GetProjectName() << '\n';
- char const* ghsGpjMacros =
+ cmProp ghsGpjMacros =
this->GetCMakeInstance()->GetCacheDefinition("GHS_GPJ_MACROS");
- if (nullptr != ghsGpjMacros) {
- std::vector<std::string> expandedList =
- cmExpandedList(std::string(ghsGpjMacros));
+ if (ghsGpjMacros) {
+ std::vector<std::string> expandedList = cmExpandedList(*ghsGpjMacros);
for (std::string const& arg : expandedList) {
fout << "macro " << arg << '\n';
}
@@ -634,17 +632,17 @@ void cmGlobalGhsMultiGenerator::WriteHighLevelDirectives(
{
/* set primary target */
std::string tgt;
- const char* t =
+ cmProp t =
this->GetCMakeInstance()->GetCacheDefinition("GHS_PRIMARY_TARGET");
if (cmNonempty(t)) {
- tgt = t;
+ tgt = *t;
this->GetCMakeInstance()->MarkCliAsUsed("GHS_PRIMARY_TARGET");
} else {
- const char* a =
+ cmProp a =
this->GetCMakeInstance()->GetCacheDefinition("CMAKE_GENERATOR_PLATFORM");
- const char* p =
+ cmProp p =
this->GetCMakeInstance()->GetCacheDefinition("GHS_TARGET_PLATFORM");
- tgt = cmStrCat((a ? a : ""), '_', (p ? p : ""), ".tgt");
+ tgt = cmStrCat((a ? *a : ""), '_', (p ? *p : ""), ".tgt");
}
/* clang-format off */
@@ -655,11 +653,11 @@ void cmGlobalGhsMultiGenerator::WriteHighLevelDirectives(
<< "/CMakeFiles/custom_target.bod" << '\n';
/* clang-format on */
- char const* const customization =
+ cmProp const customization =
this->GetCMakeInstance()->GetCacheDefinition("GHS_CUSTOMIZATION");
- if (nullptr != customization && strlen(customization) > 0) {
+ if (cmNonempty(customization)) {
fout << "customization="
- << cmGlobalGhsMultiGenerator::TrimQuotes(customization) << '\n';
+ << cmGlobalGhsMultiGenerator::TrimQuotes(*customization) << '\n';
this->GetCMakeInstance()->MarkCliAsUsed("GHS_CUSTOMIZATION");
}
}
diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx
index 37a77fa..2c934e1 100644
--- a/Source/cmGlobalUnixMakefileGenerator3.cxx
+++ b/Source/cmGlobalUnixMakefileGenerator3.cxx
@@ -104,8 +104,8 @@ std::string cmGlobalUnixMakefileGenerator3::GetEditCacheCommand() const
cmStateEnums::INTERNAL);
}
}
- const char* edit_cmd = cm->GetCacheDefinition("CMAKE_EDIT_COMMAND");
- return edit_cmd ? edit_cmd : "";
+ cmProp edit_cmd = cm->GetCacheDefinition("CMAKE_EDIT_COMMAND");
+ return edit_cmd ? *edit_cmd : std::string();
}
void cmGlobalUnixMakefileGenerator3::ComputeTargetObjectDirectory(
diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx
index 84cfaeb..6267205 100644
--- a/Source/cmGlobalVisualStudio7Generator.cxx
+++ b/Source/cmGlobalVisualStudio7Generator.cxx
@@ -625,9 +625,9 @@ std::string cmGlobalVisualStudio7Generator::WriteUtilityDepend(
std::string cmGlobalVisualStudio7Generator::GetGUID(std::string const& name)
{
std::string const& guidStoreName = name + "_GUID_CMAKE";
- if (const char* storedGUID =
+ if (cmProp storedGUID =
this->CMakeInstance->GetCacheDefinition(guidStoreName)) {
- return std::string(storedGUID);
+ return *storedGUID;
}
// Compute a GUID that is deterministic but unique to the build tree.
std::string input =
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index b57bdbc..b78f0a0 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -3140,11 +3140,10 @@ std::string cmGlobalXCodeGenerator::GetOrCreateId(const std::string& name,
const std::string& id)
{
std::string guidStoreName = cmStrCat(name, "_GUID_CMAKE");
- const char* storedGUID =
- this->CMakeInstance->GetCacheDefinition(guidStoreName);
+ cmProp storedGUID = this->CMakeInstance->GetCacheDefinition(guidStoreName);
if (storedGUID) {
- return storedGUID;
+ return *storedGUID;
}
this->CMakeInstance->AddCacheEntry(guidStoreName, id.c_str(),
diff --git a/Source/cmIfCommand.cxx b/Source/cmIfCommand.cxx
index 5808f90..fc257b1 100644
--- a/Source/cmIfCommand.cxx
+++ b/Source/cmIfCommand.cxx
@@ -75,10 +75,12 @@ bool cmIfFunctionBlocker::Replay(std::vector<cmListFileFunction> functions,
if (scopeDepth == 0 && func.Name.Lower == "else") {
if (this->ElseSeen) {
- cmListFileBacktrace bt = mf.GetBacktrace(func);
+ cmListFileBacktrace elseBT = mf.GetBacktrace().Push(
+ cmListFileContext{ func.Name.Original,
+ this->GetStartingContext().FilePath, func.Line });
mf.GetCMakeInstance()->IssueMessage(
MessageType::FATAL_ERROR,
- "A duplicate ELSE command was found inside an IF block.", bt);
+ "A duplicate ELSE command was found inside an IF block.", elseBT);
cmSystemTools::SetFatalErrorOccured();
return true;
}
@@ -93,11 +95,12 @@ bool cmIfFunctionBlocker::Replay(std::vector<cmListFileFunction> functions,
mf.PrintCommandTrace(func);
}
} else if (scopeDepth == 0 && func.Name.Lower == "elseif") {
+ cmListFileBacktrace elseifBT = mf.GetBacktrace().Push(cmListFileContext{
+ func.Name.Original, this->GetStartingContext().FilePath, func.Line });
if (this->ElseSeen) {
- cmListFileBacktrace bt = mf.GetBacktrace(func);
mf.GetCMakeInstance()->IssueMessage(
MessageType::FATAL_ERROR,
- "An ELSEIF command was found after an ELSE command.", bt);
+ "An ELSEIF command was found after an ELSE command.", elseifBT);
cmSystemTools::SetFatalErrorOccured();
return true;
}
@@ -117,12 +120,7 @@ bool cmIfFunctionBlocker::Replay(std::vector<cmListFileFunction> functions,
MessageType messType;
- cmListFileContext conditionContext =
- cmListFileContext::FromCommandContext(
- func, this->GetStartingContext().FilePath);
-
- cmConditionEvaluator conditionEvaluator(mf, conditionContext,
- mf.GetBacktrace(func));
+ cmConditionEvaluator conditionEvaluator(mf, elseifBT);
bool isTrue =
conditionEvaluator.IsTrue(expandedArguments, errorString, messType);
@@ -130,8 +128,7 @@ bool cmIfFunctionBlocker::Replay(std::vector<cmListFileFunction> functions,
if (!errorString.empty()) {
std::string err =
cmStrCat(cmIfCommandError(expandedArguments), errorString);
- cmListFileBacktrace bt = mf.GetBacktrace(func);
- mf.GetCMakeInstance()->IssueMessage(messType, err, bt);
+ mf.GetCMakeInstance()->IssueMessage(messType, err, elseifBT);
if (messType == MessageType::FATAL_ERROR) {
cmSystemTools::SetFatalErrorOccured();
return true;
@@ -178,8 +175,7 @@ bool cmIfCommand(std::vector<cmListFileArgument> const& args,
MessageType status;
- cmConditionEvaluator conditionEvaluator(
- makefile, makefile.GetExecutionContext(), makefile.GetBacktrace());
+ cmConditionEvaluator conditionEvaluator(makefile, makefile.GetBacktrace());
bool isTrue =
conditionEvaluator.IsTrue(expandedArguments, errorString, status);
diff --git a/Source/cmListFileCache.cxx b/Source/cmListFileCache.cxx
index 7ebb02f..d678b56 100644
--- a/Source/cmListFileCache.cxx
+++ b/Source/cmListFileCache.cxx
@@ -446,7 +446,8 @@ void cmListFileBacktrace::PrintCallStack(std::ostream& out) const
cmStateSnapshot bottom = this->GetBottom();
for (Entry const* cur = this->TopEntry->Parent.get(); !cur->IsBottom();
cur = cur->Parent.get()) {
- if (cur->Context.Name.empty()) {
+ if (cur->Context.Name.empty() &&
+ cur->Context.Line != cmListFileContext::DeferPlaceholderLine) {
// Skip this whole-file scope. When we get here we already will
// have printed a more-specific context within the file.
continue;
@@ -483,11 +484,13 @@ bool cmListFileBacktrace::Empty() const
std::ostream& operator<<(std::ostream& os, cmListFileContext const& lfc)
{
os << lfc.FilePath;
- if (lfc.Line) {
+ if (lfc.Line > 0) {
os << ":" << lfc.Line;
if (!lfc.Name.empty()) {
os << " (" << lfc.Name << ")";
}
+ } else if (lfc.Line == cmListFileContext::DeferPlaceholderLine) {
+ os << ":DEFERRED";
}
return os;
}
diff --git a/Source/cmListFileCache.h b/Source/cmListFileCache.h
index c9556ab..5617536 100644
--- a/Source/cmListFileCache.h
+++ b/Source/cmListFileCache.h
@@ -11,6 +11,8 @@
#include <utility>
#include <vector>
+#include <cm/optional>
+
#include "cmStateSnapshot.h"
/** \class cmListFileCache
@@ -72,14 +74,26 @@ public:
std::string Name;
std::string FilePath;
long Line = 0;
+ static long const DeferPlaceholderLine = -1;
+ cm::optional<std::string> DeferId;
+
+ cmListFileContext() = default;
+ cmListFileContext(std::string name, std::string filePath, long line)
+ : Name(std::move(name))
+ , FilePath(std::move(filePath))
+ , Line(line)
+ {
+ }
- static cmListFileContext FromCommandContext(cmCommandContext const& lfcc,
- std::string const& fileName)
+ static cmListFileContext FromCommandContext(
+ cmCommandContext const& lfcc, std::string const& fileName,
+ cm::optional<std::string> deferId = {})
{
cmListFileContext lfc;
lfc.FilePath = fileName;
lfc.Line = lfcc.Line;
lfc.Name = lfcc.Name.Original;
+ lfc.DeferId = std::move(deferId);
return lfc;
}
};
diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx
index 504268e..fdf8307 100644
--- a/Source/cmLocalVisualStudio7Generator.cxx
+++ b/Source/cmLocalVisualStudio7Generator.cxx
@@ -1081,11 +1081,13 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(
if (stackVal) {
fout << "\t\t\t\tStackReserveSize=\"" << *stackVal << "\"\n";
}
- temp = cmStrCat(
- target->GetDirectory(configName, cmStateEnums::ImportLibraryArtifact),
- '/', targetNames.ImportLibrary);
- fout << "\t\t\t\tImportLibrary=\""
- << this->ConvertToXMLOutputPathSingle(temp) << "\"";
+ if (!targetNames.ImportLibrary.empty()) {
+ temp = cmStrCat(target->GetDirectory(
+ configName, cmStateEnums::ImportLibraryArtifact),
+ '/', targetNames.ImportLibrary);
+ fout << "\t\t\t\tImportLibrary=\""
+ << this->ConvertToXMLOutputPathSingle(temp) << "\"";
+ }
if (this->FortranProject) {
fout << "\n\t\t\t\tLinkDLL=\"true\"";
}
diff --git a/Source/cmMacroCommand.cxx b/Source/cmMacroCommand.cxx
index c88b343..91a600e 100644
--- a/Source/cmMacroCommand.cxx
+++ b/Source/cmMacroCommand.cxx
@@ -157,8 +157,7 @@ bool cmMacroFunctionBlocker::ArgumentsMatch(cmListFileFunction const& lff,
cmMakefile& mf) const
{
std::vector<std::string> expandedArguments;
- mf.ExpandArguments(lff.Arguments, expandedArguments,
- this->GetStartingContext().FilePath.c_str());
+ mf.ExpandArguments(lff.Arguments, expandedArguments);
return expandedArguments.empty() || expandedArguments[0] == this->Args[0];
}
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index d77c4af..ac3a193 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -16,6 +16,7 @@
#include <cm/iterator>
#include <cm/memory>
#include <cm/optional>
+#include <cm/type_traits> // IWYU pragma: keep
#include <cm/vector>
#include <cmext/algorithm>
#include <cmext/string_view>
@@ -274,31 +275,14 @@ cmListFileBacktrace cmMakefile::GetBacktrace() const
return this->Backtrace;
}
-cmListFileBacktrace cmMakefile::GetBacktrace(cmCommandContext const& cc) const
-{
- cmListFileContext lfc;
- lfc.Name = cc.Name.Original;
- lfc.Line = cc.Line;
- lfc.FilePath = this->StateSnapshot.GetExecutionListFile();
- return this->Backtrace.Push(lfc);
-}
-
-cmListFileContext cmMakefile::GetExecutionContext() const
-{
- cmListFileContext const& cur = this->Backtrace.Top();
- cmListFileContext lfc;
- lfc.Name = cur.Name;
- lfc.Line = cur.Line;
- lfc.FilePath = this->StateSnapshot.GetExecutionListFile();
- return lfc;
-}
-
-void cmMakefile::PrintCommandTrace(const cmListFileFunction& lff) const
+void cmMakefile::PrintCommandTrace(
+ cmListFileFunction const& lff,
+ cm::optional<std::string> const& deferId) const
{
// Check if current file in the list of requested to trace...
std::vector<std::string> const& trace_only_this_files =
this->GetCMakeInstance()->GetTraceSources();
- std::string const& full_path = this->GetExecutionFilePath();
+ std::string const& full_path = this->GetBacktrace().Top().FilePath;
std::string const& only_filename = cmSystemTools::GetFilenameName(full_path);
bool trace = trace_only_this_files.empty();
if (!trace) {
@@ -341,6 +325,9 @@ void cmMakefile::PrintCommandTrace(const cmListFileFunction& lff) const
builder["indentation"] = "";
val["file"] = full_path;
val["line"] = static_cast<Json::Value::Int64>(lff.Line);
+ if (deferId) {
+ val["defer"] = *deferId;
+ }
val["cmd"] = lff.Name.Original;
val["args"] = Json::Value(Json::arrayValue);
for (std::string const& arg : args) {
@@ -354,8 +341,11 @@ void cmMakefile::PrintCommandTrace(const cmListFileFunction& lff) const
break;
}
case cmake::TraceFormat::TRACE_HUMAN:
- msg << full_path << "(" << lff.Line << "): ";
- msg << lff.Name.Original << "(";
+ msg << full_path << "(" << lff.Line << "):";
+ if (deferId) {
+ msg << "DEFERRED:" << *deferId << ":";
+ }
+ msg << " " << lff.Name.Original << "(";
for (std::string const& arg : args) {
msg << arg << " ";
@@ -380,11 +370,12 @@ class cmMakefileCall
{
public:
cmMakefileCall(cmMakefile* mf, cmListFileFunction const& lff,
- cmExecutionStatus& status)
+ cm::optional<std::string> deferId, cmExecutionStatus& status)
: Makefile(mf)
{
cmListFileContext const& lfc = cmListFileContext::FromCommandContext(
- lff, this->Makefile->StateSnapshot.GetExecutionListFile());
+ lff, this->Makefile->StateSnapshot.GetExecutionListFile(),
+ std::move(deferId));
this->Makefile->Backtrace = this->Makefile->Backtrace.Push(lfc);
++this->Makefile->RecursionDepth;
this->Makefile->ExecutionStatusStack.push_back(&status);
@@ -421,7 +412,8 @@ void cmMakefile::OnExecuteCommand(std::function<void()> callback)
}
bool cmMakefile::ExecuteCommand(const cmListFileFunction& lff,
- cmExecutionStatus& status)
+ cmExecutionStatus& status,
+ cm::optional<std::string> deferId)
{
bool result = true;
@@ -436,7 +428,7 @@ bool cmMakefile::ExecuteCommand(const cmListFileFunction& lff,
}
// Place this call on the call stack.
- cmMakefileCall stack_manager(this, lff, status);
+ cmMakefileCall stack_manager(this, lff, std::move(deferId), status);
static_cast<void>(stack_manager);
// Check for maximum recursion depth.
@@ -464,7 +456,7 @@ bool cmMakefile::ExecuteCommand(const cmListFileFunction& lff,
if (!cmSystemTools::GetFatalErrorOccured()) {
// if trace is enabled, print out invoke information
if (this->GetCMakeInstance()->GetTrace()) {
- this->PrintCommandTrace(lff);
+ this->PrintCommandTrace(lff, this->Backtrace.Top().DeferId);
}
// Try invoking the command.
bool invokeSucceeded = command(lff.Arguments, status);
@@ -597,7 +589,7 @@ void cmMakefile::IncludeScope::EnforceCMP0011()
std::ostringstream w;
w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0011) << "\n"
<< "The included script\n "
- << this->Makefile->GetExecutionFilePath() << "\n"
+ << this->Makefile->GetBacktrace().Top().FilePath << "\n"
<< "affects policy settings. "
<< "CMake is implying the NO_POLICY_SCOPE option for compatibility, "
<< "so the effects are applied to the including context.";
@@ -610,7 +602,7 @@ void cmMakefile::IncludeScope::EnforceCMP0011()
/* clang-format off */
e << cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0011) << "\n"
<< "The included script\n "
- << this->Makefile->GetExecutionFilePath() << "\n"
+ << this->Makefile->GetBacktrace().Top().FilePath << "\n"
<< "affects policy settings, so it requires this policy to be set.";
/* clang-format on */
this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
@@ -641,7 +633,7 @@ bool cmMakefile::ReadDependentFile(const std::string& filename,
return false;
}
- this->ReadListFile(listFile, filenametoread);
+ this->RunListFile(listFile, filenametoread);
if (cmSystemTools::GetFatalErrorOccured()) {
incScope.Quiet();
}
@@ -682,6 +674,53 @@ private:
bool ReportError;
};
+class cmMakefile::DeferScope
+{
+public:
+ DeferScope(cmMakefile* mf, std::string const& deferredInFile)
+ : Makefile(mf)
+ {
+ cmListFileContext lfc;
+ lfc.Line = cmListFileContext::DeferPlaceholderLine;
+ lfc.FilePath = deferredInFile;
+ this->Makefile->Backtrace = this->Makefile->Backtrace.Push(lfc);
+ this->Makefile->DeferRunning = true;
+ }
+
+ ~DeferScope()
+ {
+ this->Makefile->DeferRunning = false;
+ this->Makefile->Backtrace = this->Makefile->Backtrace.Pop();
+ }
+
+ DeferScope(const DeferScope&) = delete;
+ DeferScope& operator=(const DeferScope&) = delete;
+
+private:
+ cmMakefile* Makefile;
+};
+
+class cmMakefile::DeferCallScope
+{
+public:
+ DeferCallScope(cmMakefile* mf, std::string const& deferredFromFile)
+ : Makefile(mf)
+ {
+ this->Makefile->StateSnapshot =
+ this->Makefile->GetState()->CreateDeferCallSnapshot(
+ this->Makefile->StateSnapshot, deferredFromFile);
+ assert(this->Makefile->StateSnapshot.IsValid());
+ }
+
+ ~DeferCallScope() { this->Makefile->PopSnapshot(); }
+
+ DeferCallScope(const DeferCallScope&) = delete;
+ DeferCallScope& operator=(const DeferCallScope&) = delete;
+
+private:
+ cmMakefile* Makefile;
+};
+
bool cmMakefile::ReadListFile(const std::string& filename)
{
std::string filenametoread = cmSystemTools::CollapseFullPath(
@@ -695,7 +734,7 @@ bool cmMakefile::ReadListFile(const std::string& filename)
return false;
}
- this->ReadListFile(listFile, filenametoread);
+ this->RunListFile(listFile, filenametoread);
if (cmSystemTools::GetFatalErrorOccured()) {
scope.Quiet();
}
@@ -716,15 +755,16 @@ bool cmMakefile::ReadListFileAsString(const std::string& content,
return false;
}
- this->ReadListFile(listFile, filenametoread);
+ this->RunListFile(listFile, filenametoread);
if (cmSystemTools::GetFatalErrorOccured()) {
scope.Quiet();
}
return true;
}
-void cmMakefile::ReadListFile(cmListFile const& listFile,
- std::string const& filenametoread)
+void cmMakefile::RunListFile(cmListFile const& listFile,
+ std::string const& filenametoread,
+ DeferCommands* defer)
{
// add this list file to the list of dependencies
this->ListFiles.push_back(filenametoread);
@@ -755,6 +795,33 @@ void cmMakefile::ReadListFile(cmListFile const& listFile,
}
}
+ // Run any deferred commands.
+ if (defer) {
+ // Add a backtrace level indicating calls are deferred.
+ DeferScope scope(this, filenametoread);
+
+ // Iterate by index in case one deferred call schedules another.
+ // NOLINTNEXTLINE(modernize-loop-convert)
+ for (size_t i = 0; i < defer->Commands.size(); ++i) {
+ DeferCommand& d = defer->Commands[i];
+ if (d.Id.empty()) {
+ // Cancelled.
+ continue;
+ }
+ // Mark as executed.
+ std::string id = std::move(d.Id);
+
+ // The deferred call may have come from another file.
+ DeferCallScope callScope(this, d.FilePath);
+
+ cmExecutionStatus status(*this);
+ this->ExecuteCommand(d.Command, status, std::move(id));
+ if (cmSystemTools::GetFatalErrorOccured()) {
+ break;
+ }
+ }
+ }
+
this->AddDefinition("CMAKE_PARENT_LIST_FILE", currentParentFile);
this->AddDefinition("CMAKE_CURRENT_LIST_FILE", currentFile);
this->AddDefinition("CMAKE_CURRENT_LIST_DIR",
@@ -1697,7 +1764,9 @@ void cmMakefile::Configure()
}
}
- this->ReadListFile(listFile, currentStart);
+ this->Defer = cm::make_unique<DeferCommands>();
+ this->RunListFile(listFile, currentStart, this->Defer.get());
+ this->Defer.reset();
if (cmSystemTools::GetFatalErrorOccured()) {
scope.Quiet();
}
@@ -1772,6 +1841,13 @@ void cmMakefile::AddSubDirectory(const std::string& srcPath,
const std::string& binPath,
bool excludeFromAll, bool immediate)
{
+ if (this->DeferRunning) {
+ this->IssueMessage(
+ MessageType::FATAL_ERROR,
+ "Subdirectories may not be created during deferred execution.");
+ return;
+ }
+
// Make sure the binary directory is unique.
if (!this->EnforceUniqueDir(srcPath, binPath)) {
return;
@@ -2979,6 +3055,68 @@ void cmMakefile::SetRecursionDepth(int recursionDepth)
this->RecursionDepth = recursionDepth;
}
+std::string cmMakefile::NewDeferId()
+{
+ return this->GetGlobalGenerator()->NewDeferId();
+}
+
+bool cmMakefile::DeferCall(std::string id, std::string file,
+ cmListFileFunction lff)
+{
+ if (!this->Defer) {
+ return false;
+ }
+ this->Defer->Commands.emplace_back(
+ DeferCommand{ std::move(id), std::move(file), std::move(lff) });
+ return true;
+}
+
+bool cmMakefile::DeferCancelCall(std::string const& id)
+{
+ if (!this->Defer) {
+ return false;
+ }
+ for (DeferCommand& dc : this->Defer->Commands) {
+ if (dc.Id == id) {
+ dc.Id.clear();
+ }
+ }
+ return true;
+}
+
+cm::optional<std::string> cmMakefile::DeferGetCallIds() const
+{
+ cm::optional<std::string> ids;
+ if (this->Defer) {
+ ids = cmJoin(
+ cmMakeRange(this->Defer->Commands)
+ .filter([](DeferCommand const& dc) -> bool { return !dc.Id.empty(); })
+ .transform(
+ [](DeferCommand const& dc) -> std::string const& { return dc.Id; }),
+ ";");
+ }
+ return ids;
+}
+
+cm::optional<std::string> cmMakefile::DeferGetCall(std::string const& id) const
+{
+ cm::optional<std::string> call;
+ if (this->Defer) {
+ std::string tmp;
+ for (DeferCommand const& dc : this->Defer->Commands) {
+ if (dc.Id == id) {
+ tmp = dc.Command.Name.Original;
+ for (cmListFileArgument const& arg : dc.Command.Arguments) {
+ tmp = cmStrCat(tmp, ';', arg.Value);
+ }
+ break;
+ }
+ }
+ call = std::move(tmp);
+ }
+ return call;
+}
+
MessageType cmMakefile::ExpandVariablesInStringNew(
std::string& errorstr, std::string& source, bool escapeQuotes,
bool noEscapes, bool atOnly, const char* filename, long line,
@@ -3016,7 +3154,12 @@ MessageType cmMakefile::ExpandVariablesInStringNew(
switch (var.domain) {
case NORMAL:
if (filename && lookup == lineVar) {
- varresult = std::to_string(line);
+ cmListFileContext const& top = this->Backtrace.Top();
+ if (top.DeferId) {
+ varresult = cmStrCat("DEFERRED:"_s, *top.DeferId);
+ } else {
+ varresult = std::to_string(line);
+ }
} else {
value = this->GetDefinition(lookup);
}
@@ -3347,20 +3490,10 @@ bool cmMakefile::IsLoopBlock() const
return !this->LoopBlockCounter.empty() && this->LoopBlockCounter.top() > 0;
}
-std::string const& cmMakefile::GetExecutionFilePath() const
-{
- assert(this->StateSnapshot.IsValid());
- return this->StateSnapshot.GetExecutionListFile();
-}
-
bool cmMakefile::ExpandArguments(std::vector<cmListFileArgument> const& inArgs,
- std::vector<std::string>& outArgs,
- const char* filename) const
+ std::vector<std::string>& outArgs) const
{
- if (!filename) {
- auto const& efp = this->GetExecutionFilePath();
- filename = efp.c_str();
- }
+ std::string const& filename = this->GetBacktrace().Top().FilePath;
std::string value;
outArgs.reserve(inArgs.size());
for (cmListFileArgument const& i : inArgs) {
@@ -3371,8 +3504,8 @@ bool cmMakefile::ExpandArguments(std::vector<cmListFileArgument> const& inArgs,
}
// Expand the variables in the argument.
value = i.Value;
- this->ExpandVariablesInString(value, false, false, false, filename, i.Line,
- false, false);
+ this->ExpandVariablesInString(value, false, false, false, filename.c_str(),
+ i.Line, false, false);
// If the argument is quoted, it should be one argument.
// Otherwise, it may be a list of arguments.
@@ -3387,12 +3520,9 @@ bool cmMakefile::ExpandArguments(std::vector<cmListFileArgument> const& inArgs,
bool cmMakefile::ExpandArguments(
std::vector<cmListFileArgument> const& inArgs,
- std::vector<cmExpandedCommandArgument>& outArgs, const char* filename) const
+ std::vector<cmExpandedCommandArgument>& outArgs) const
{
- if (!filename) {
- auto const& efp = this->GetExecutionFilePath();
- filename = efp.c_str();
- }
+ std::string const& filename = this->GetBacktrace().Top().FilePath;
std::string value;
outArgs.reserve(inArgs.size());
for (cmListFileArgument const& i : inArgs) {
@@ -3403,8 +3533,8 @@ bool cmMakefile::ExpandArguments(
}
// Expand the variables in the argument.
value = i.Value;
- this->ExpandVariablesInString(value, false, false, false, filename, i.Line,
- false, false);
+ this->ExpandVariablesInString(value, false, false, false, filename.c_str(),
+ i.Line, false, false);
// If the argument is quoted, it should be one argument.
// Otherwise, it may be a list of arguments.
@@ -3424,7 +3554,7 @@ void cmMakefile::AddFunctionBlocker(std::unique_ptr<cmFunctionBlocker> fb)
{
if (!this->ExecutionStatusStack.empty()) {
// Record the context in which the blocker is created.
- fb->SetStartingContext(this->GetExecutionContext());
+ fb->SetStartingContext(this->Backtrace.Top());
}
this->FunctionBlockers.push(std::move(fb));
@@ -3593,6 +3723,12 @@ void cmMakefile::AddTargetObject(std::string const& tgtName,
void cmMakefile::EnableLanguage(std::vector<std::string> const& lang,
bool optional)
{
+ if (this->DeferRunning) {
+ this->IssueMessage(
+ MessageType::FATAL_ERROR,
+ "Languages may not be enabled during deferred execution.");
+ return;
+ }
if (const char* def = this->GetGlobalGenerator()->GetCMakeCFGIntDir()) {
this->AddDefinition("CMAKE_CFG_INTDIR", def);
}
diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h
index 0a6e6e2..c7940fb 100644
--- a/Source/cmMakefile.h
+++ b/Source/cmMakefile.h
@@ -15,6 +15,7 @@
#include <unordered_map>
#include <vector>
+#include <cm/optional>
#include <cm/string_view>
#include "cmsys/RegularExpression.hxx"
@@ -640,8 +641,6 @@ public:
* Get the current context backtrace.
*/
cmListFileBacktrace GetBacktrace() const;
- cmListFileBacktrace GetBacktrace(cmCommandContext const& lfc) const;
- cmListFileContext GetExecutionContext() const;
/**
* Get the vector of files created by this makefile
@@ -697,7 +696,8 @@ public:
/**
* Print a command's invocation
*/
- void PrintCommandTrace(const cmListFileFunction& lff) const;
+ void PrintCommandTrace(cmListFileFunction const& lff,
+ cm::optional<std::string> const& deferId = {}) const;
/**
* Set a callback that is invoked whenever ExecuteCommand is called.
@@ -708,8 +708,8 @@ public:
* Execute a single CMake command. Returns true if the command
* succeeded or false if it failed.
*/
- bool ExecuteCommand(const cmListFileFunction& lff,
- cmExecutionStatus& status);
+ bool ExecuteCommand(const cmListFileFunction& lff, cmExecutionStatus& status,
+ cm::optional<std::string> deferId = {});
//! Enable support for named language, if nil then all languages are
/// enabled.
@@ -734,12 +734,9 @@ public:
* variable replacement and list expansion.
*/
bool ExpandArguments(std::vector<cmListFileArgument> const& inArgs,
- std::vector<std::string>& outArgs,
- const char* filename = nullptr) const;
-
+ std::vector<std::string>& outArgs) const;
bool ExpandArguments(std::vector<cmListFileArgument> const& inArgs,
- std::vector<cmExpandedCommandArgument>& outArgs,
- const char* filename = nullptr) const;
+ std::vector<cmExpandedCommandArgument>& outArgs) const;
/**
* Get the instance
@@ -942,8 +939,6 @@ public:
const char* GetDefineFlagsCMP0059() const;
- std::string const& GetExecutionFilePath() const;
-
void EnforceDirectoryLevelRules() const;
void AddEvaluationFile(
@@ -972,6 +967,12 @@ public:
int GetRecursionDepth() const;
void SetRecursionDepth(int recursionDepth);
+ std::string NewDeferId();
+ bool DeferCall(std::string id, std::string fileName, cmListFileFunction lff);
+ bool DeferCancelCall(std::string const& id);
+ cm::optional<std::string> DeferGetCallIds() const;
+ cm::optional<std::string> DeferGetCall(std::string const& id) const;
+
protected:
// add link libraries and directories to the target
void AddGlobalLinkInformation(cmTarget& target);
@@ -1033,10 +1034,25 @@ private:
cmListFileBacktrace Backtrace;
int RecursionDepth;
+ struct DeferCommand
+ {
+ // Id is empty for an already-executed or cancelled operation.
+ std::string Id;
+ std::string FilePath;
+ cmListFileFunction Command;
+ };
+ struct DeferCommands
+ {
+ std::vector<DeferCommand> Commands;
+ };
+ std::unique_ptr<DeferCommands> Defer;
+ bool DeferRunning = false;
+
void DoGenerate(cmLocalGenerator& lg);
- void ReadListFile(cmListFile const& listFile,
- const std::string& filenametoread);
+ void RunListFile(cmListFile const& listFile,
+ const std::string& filenametoread,
+ DeferCommands* defer = nullptr);
bool ParseDefineFlag(std::string const& definition, bool remove);
@@ -1087,6 +1103,12 @@ private:
class ListFileScope;
friend class ListFileScope;
+ class DeferScope;
+ friend class DeferScope;
+
+ class DeferCallScope;
+ friend class DeferCallScope;
+
class BuildsystemFileScope;
friend class BuildsystemFileScope;
diff --git a/Source/cmState.cxx b/Source/cmState.cxx
index e96c82f..d5ac9ae 100644
--- a/Source/cmState.cxx
+++ b/Source/cmState.cxx
@@ -837,6 +837,21 @@ cmStateSnapshot cmState::CreateBuildsystemDirectorySnapshot(
return snapshot;
}
+cmStateSnapshot cmState::CreateDeferCallSnapshot(
+ cmStateSnapshot const& originSnapshot, std::string const& fileName)
+{
+ cmStateDetail::PositionType pos =
+ this->SnapshotData.Push(originSnapshot.Position, *originSnapshot.Position);
+ pos->SnapshotType = cmStateEnums::DeferCallType;
+ pos->Keep = false;
+ pos->ExecutionListFile = this->ExecutionListFiles.Push(
+ originSnapshot.Position->ExecutionListFile, fileName);
+ assert(originSnapshot.Position->Vars.IsValid());
+ pos->BuildSystemDirectory->DirectoryEnd = pos;
+ pos->PolicyScope = originSnapshot.Position->Policies;
+ return { this, pos };
+}
+
cmStateSnapshot cmState::CreateFunctionCallSnapshot(
cmStateSnapshot const& originSnapshot, std::string const& fileName)
{
diff --git a/Source/cmState.h b/Source/cmState.h
index dc3ba65..2aa57e0 100644
--- a/Source/cmState.h
+++ b/Source/cmState.h
@@ -55,6 +55,8 @@ public:
cmStateSnapshot CreateBaseSnapshot();
cmStateSnapshot CreateBuildsystemDirectorySnapshot(
cmStateSnapshot const& originSnapshot);
+ cmStateSnapshot CreateDeferCallSnapshot(
+ cmStateSnapshot const& originSnapshot, std::string const& fileName);
cmStateSnapshot CreateFunctionCallSnapshot(
cmStateSnapshot const& originSnapshot, std::string const& fileName);
cmStateSnapshot CreateMacroCallSnapshot(
diff --git a/Source/cmStateTypes.h b/Source/cmStateTypes.h
index b8c1cca..010d7e3 100644
--- a/Source/cmStateTypes.h
+++ b/Source/cmStateTypes.h
@@ -18,6 +18,7 @@ enum SnapshotType
{
BaseType,
BuildsystemDirectoryType,
+ DeferCallType,
FunctionCallType,
MacroCallType,
IncludeFileType,
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index fbf4ceb..1e625a4 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -5,7 +5,8 @@
// POSIX APIs are needed
# define _POSIX_C_SOURCE 200809L
#endif
-#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__)
+#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || \
+ defined(__QNX__)
// For isascii
# define _XOPEN_SOURCE 700
#endif
diff --git a/Source/cmTargetLinkLibrariesCommand.cxx b/Source/cmTargetLinkLibrariesCommand.cxx
index 7db2c46..aecc18e 100644
--- a/Source/cmTargetLinkLibrariesCommand.cxx
+++ b/Source/cmTargetLinkLibrariesCommand.cxx
@@ -10,6 +10,7 @@
#include "cmExecutionStatus.h"
#include "cmGeneratorExpression.h"
#include "cmGlobalGenerator.h"
+#include "cmListFileCache.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmPolicies.h"
@@ -386,7 +387,7 @@ bool TLL::HandleLibrary(ProcessingState currentProcessingState,
? cmTarget::KeywordTLLSignature
: cmTarget::PlainTLLSignature;
if (!this->Target->PushTLLCommandTrace(
- sig, this->Makefile.GetExecutionContext())) {
+ sig, this->Makefile.GetBacktrace().Top())) {
std::ostringstream e;
const char* modal = nullptr;
MessageType messageType = MessageType::AUTHOR_WARNING;
diff --git a/Source/cmTimestamp.cxx b/Source/cmTimestamp.cxx
index bd6bb3d..67f7e11 100644
--- a/Source/cmTimestamp.cxx
+++ b/Source/cmTimestamp.cxx
@@ -5,7 +5,8 @@
// POSIX APIs are needed
# define _POSIX_C_SOURCE 200809L
#endif
-#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__)
+#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || \
+ defined(__QNX__)
// For isascii
# define _XOPEN_SOURCE 700
#endif
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index 326ab15..413166e 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -2869,6 +2869,23 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions(
this->Makefile->IsOn("CMAKE_VERBOSE_MAKEFILE"));
}
+ // Add C-specific flags expressible in a ClCompile meant for C++.
+ if (langForClCompile == "CXX") {
+ std::set<std::string> languages;
+ this->GeneratorTarget->GetLanguages(languages, configName);
+ if (languages.count("C")) {
+ std::string flagsC;
+ this->LocalGenerator->AddCompileOptions(flagsC, this->GeneratorTarget,
+ "C", configName);
+ Options optC(this->LocalGenerator, Options::Compiler,
+ gg->GetClFlagTable());
+ optC.Parse(flagsC);
+ if (const char* stdC = optC.GetFlag("LanguageStandard_C")) {
+ clOptions.AddFlag("LanguageStandard_C", stdC);
+ }
+ }
+ }
+
// Add a definition for the configuration name.
std::string configDefine = cmStrCat("CMAKE_INTDIR=\"", configName, '"');
clOptions.AddDefine(configDefine);
@@ -3775,12 +3792,14 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions(
std::string pdb = cmStrCat(this->GeneratorTarget->GetPDBDirectory(config),
'/', targetNames.PDB);
- std::string imLib =
- cmStrCat(this->GeneratorTarget->GetDirectory(
- config, cmStateEnums::ImportLibraryArtifact),
- '/', targetNames.ImportLibrary);
+ if (!targetNames.ImportLibrary.empty()) {
+ std::string imLib =
+ cmStrCat(this->GeneratorTarget->GetDirectory(
+ config, cmStateEnums::ImportLibraryArtifact),
+ '/', targetNames.ImportLibrary);
- linkOptions.AddFlag("ImportLibrary", imLib);
+ linkOptions.AddFlag("ImportLibrary", imLib);
+ }
linkOptions.AddFlag("ProgramDataBaseFile", pdb);
// A Windows Runtime component uses internal .NET metadata,
diff --git a/Source/cmWhileCommand.cxx b/Source/cmWhileCommand.cxx
index 0d8e894..2c7a8a7 100644
--- a/Source/cmWhileCommand.cxx
+++ b/Source/cmWhileCommand.cxx
@@ -17,6 +17,7 @@
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmSystemTools.h"
+#include "cmake.h"
class cmWhileFunctionBlocker : public cmFunctionBlocker
{
@@ -66,14 +67,9 @@ bool cmWhileFunctionBlocker::Replay(std::vector<cmListFileFunction> functions,
mf.ExpandArguments(this->Args, expandedArguments);
MessageType messageType;
- cmListFileContext execContext = this->GetStartingContext();
-
- cmCommandContext commandContext;
- commandContext.Line = execContext.Line;
- commandContext.Name = execContext.Name;
-
- cmConditionEvaluator conditionEvaluator(mf, this->GetStartingContext(),
- mf.GetBacktrace(commandContext));
+ cmListFileBacktrace whileBT =
+ mf.GetBacktrace().Push(this->GetStartingContext());
+ cmConditionEvaluator conditionEvaluator(mf, whileBT);
bool isTrue =
conditionEvaluator.IsTrue(expandedArguments, errorString, messageType);
@@ -90,7 +86,7 @@ bool cmWhileFunctionBlocker::Replay(std::vector<cmListFileFunction> functions,
err += "(";
err += errorString;
err += ").";
- mf.IssueMessage(messageType, err);
+ mf.GetCMakeInstance()->IssueMessage(messageType, err, whileBT);
if (messageType == MessageType::FATAL_ERROR) {
cmSystemTools::SetFatalErrorOccured();
return true;
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index bca938e..dc06fae 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -983,7 +983,7 @@ void cmake::PrintTraceFormatVersion()
Json::StreamWriterBuilder builder;
builder["indentation"] = "";
version["major"] = 1;
- version["minor"] = 0;
+ version["minor"] = 1;
val["version"] = version;
msg = Json::writeString(builder, val);
#endif
@@ -2000,10 +2000,9 @@ std::string cmake::StripExtension(const std::string& file) const
return file;
}
-const char* cmake::GetCacheDefinition(const std::string& name) const
+cmProp cmake::GetCacheDefinition(const std::string& name) const
{
- cmProp p = this->State->GetInitializedCacheValue(name);
- return p ? p->c_str() : nullptr;
+ return this->State->GetInitializedCacheValue(name);
}
void cmake::AddScriptingCommands()
diff --git a/Source/cmake.h b/Source/cmake.h
index 44c35c2..63635cb 100644
--- a/Source/cmake.h
+++ b/Source/cmake.h
@@ -299,7 +299,7 @@ public:
/**
* Given a variable name, return its value (as a string).
*/
- const char* GetCacheDefinition(const std::string&) const;
+ cmProp GetCacheDefinition(const std::string&) const;
//! Add an entry into the cache
void AddCacheEntry(const std::string& key, const char* value,
const char* helpString, int type);
diff --git a/Source/kwsys/RegularExpression.cxx b/Source/kwsys/RegularExpression.cxx
index 4f74eba..fb4e380 100644
--- a/Source/kwsys/RegularExpression.cxx
+++ b/Source/kwsys/RegularExpression.cxx
@@ -359,7 +359,7 @@ bool RegularExpression::compile(const char* exp)
this->regmatch.clear();
// Small enough for pointer-storage convention?
- if (comp.regsize >= 32767L) { // Probably could be 65535L.
+ if (comp.regsize >= 65535L) {
// RAISE Error, SYM(RegularExpression), SYM(Expr_Too_Big),
printf("RegularExpression::compile(): Expression too big.\n");
return false;
diff --git a/Templates/MSBuild/FlagTables/v142_CL.json b/Templates/MSBuild/FlagTables/v142_CL.json
index 95b9d14..7c2d291 100644
--- a/Templates/MSBuild/FlagTables/v142_CL.json
+++ b/Templates/MSBuild/FlagTables/v142_CL.json
@@ -455,6 +455,20 @@
"flags": []
},
{
+ "name": "LanguageStandard_C",
+ "switch": "std:c11",
+ "comment": "ISO C11 Standard",
+ "value": "stdc11",
+ "flags": []
+ },
+ {
+ "name": "LanguageStandard_C",
+ "switch": "std:c17",
+ "comment": "ISO C17 (2018) Standard",
+ "value": "stdc17",
+ "flags": []
+ },
+ {
"name": "PrecompiledHeader",
"switch": "Yc",
"comment": "Create",
diff --git a/Tests/CMakeGUI/CMakeGUITest.cmake b/Tests/CMakeGUI/CMakeGUITest.cmake
index 3d8c27e..b60ec35 100644
--- a/Tests/CMakeGUI/CMakeGUITest.cmake
+++ b/Tests/CMakeGUI/CMakeGUITest.cmake
@@ -109,3 +109,12 @@ run_cmake_gui_test(sourceBinaryArgs:noExistConfigExists
ARGS
"${CMakeGUITest_BINARY_DIR}/sourceBinaryArgs-noExistConfigExists/noexist"
)
+
+run_cmake_gui_test(simpleConfigure:success)
+run_cmake_gui_test(simpleConfigure:fail)
+
+unset(ENV{ADDED_VARIABLE})
+set(ENV{KEPT_VARIABLE} "Kept variable")
+set(ENV{CHANGED_VARIABLE} "This variable will be changed")
+set(ENV{REMOVED_VARIABLE} "Removed variable")
+run_cmake_gui_test(environment)
diff --git a/Tests/CMakeGUI/CMakeGUITest.cxx b/Tests/CMakeGUI/CMakeGUITest.cxx
index a7a5d17..80ea08d 100644
--- a/Tests/CMakeGUI/CMakeGUITest.cxx
+++ b/Tests/CMakeGUI/CMakeGUITest.cxx
@@ -2,8 +2,10 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "CMakeGUITest.h"
+#include "QCMake.h"
#include <QApplication>
#include <QEventLoop>
+#include <QMessageBox>
#include <QSettings>
#include <QString>
#include <QStringList>
@@ -13,6 +15,9 @@
#include "CMakeSetupDialog.h"
+#include "CatchShow.h"
+#include "FirstConfigure.h"
+
namespace {
void loopSleep(int msecs = 100)
{
@@ -28,6 +33,44 @@ CMakeGUITest::CMakeGUITest(CMakeSetupDialog* window, QObject* parent)
{
}
+void CMakeGUITest::tryConfigure(int expectedResult, int timeout)
+{
+ auto* cmake = this->m_window->findChild<QCMakeThread*>()->cmakeInstance();
+
+ bool done = false;
+ CatchShow catchConfigure;
+ catchConfigure.setCallback<FirstConfigure>([&done](FirstConfigure* dialog) {
+ if (done) {
+ return;
+ }
+ done = true;
+
+ dialog->findChild<StartCompilerSetup*>()->setCurrentGenerator(
+ CMAKE_GENERATOR);
+ dialog->accept();
+ });
+
+ CatchShow catchMessages;
+ catchMessages.setCallback<QMessageBox>([](QMessageBox* box) {
+ if (box->text().contains("Build directory does not exist")) {
+ box->accept();
+ }
+
+ if (box->text().contains("Error in configuration process")) {
+ box->accept();
+ }
+ });
+
+ QSignalSpy configureDoneSpy(cmake, &QCMake::configureDone);
+ QVERIFY(configureDoneSpy.isValid());
+ QMetaObject::invokeMethod(
+ this->m_window, [this]() { this->m_window->ConfigureButton->click(); },
+ Qt::QueuedConnection);
+ QVERIFY(configureDoneSpy.wait(timeout));
+
+ QCOMPARE(configureDoneSpy, { { expectedResult } });
+}
+
void CMakeGUITest::sourceBinaryArgs()
{
QFETCH(QString, sourceDir);
@@ -68,6 +111,67 @@ void CMakeGUITest::sourceBinaryArgs_data()
<< CMakeGUITest_BINARY_DIR "/sourceBinaryArgs-noExistConfigExists/build";
}
+void CMakeGUITest::simpleConfigure()
+{
+ QFETCH(QString, sourceDir);
+ QFETCH(QString, binaryDir);
+ QFETCH(int, expectedResult);
+
+ this->m_window->SourceDirectory->setText(sourceDir);
+ this->m_window->BinaryDirectory->setCurrentText(binaryDir);
+
+ // Wait a bit for everything to update
+ loopSleep();
+
+ this->tryConfigure(expectedResult, 1000);
+}
+
+void CMakeGUITest::simpleConfigure_data()
+{
+ QTest::addColumn<QString>("sourceDir");
+ QTest::addColumn<QString>("binaryDir");
+ QTest::addColumn<int>("expectedResult");
+
+ QTest::newRow("success") << CMakeGUITest_BINARY_DIR
+ "/simpleConfigure-success/src"
+ << CMakeGUITest_BINARY_DIR
+ "/simpleConfigure-success/build"
+ << 0;
+ QTest::newRow("fail") << CMakeGUITest_BINARY_DIR "/simpleConfigure-fail/src"
+ << CMakeGUITest_BINARY_DIR
+ "/simpleConfigure-fail/build"
+ << -1;
+}
+
+void CMakeGUITest::environment()
+{
+ auto* cmake = this->m_window->findChild<QCMakeThread*>()->cmakeInstance();
+
+ this->m_window->SourceDirectory->setText(CMakeGUITest_BINARY_DIR
+ "/environment/src");
+ this->m_window->BinaryDirectory->setCurrentText(CMakeGUITest_BINARY_DIR
+ "/environment/build");
+
+ // We are already testing EnvironmentDialog, so just trust that it's
+ // connected correctly and modify the environment directly.
+ auto env = cmake->environment();
+ env.insert("ADDED_VARIABLE", "Added variable");
+ env.insert("CHANGED_VARIABLE", "Changed variable");
+ env.remove("REMOVED_VARIABLE");
+ cmake->setEnvironment(env);
+
+ // Wait a bit for everything to update
+ loopSleep();
+
+ this->tryConfigure();
+
+ auto penv = QProcessEnvironment::systemEnvironment();
+ QVERIFY(!penv.contains("ADDED_VARIABLE"));
+ QCOMPARE(penv.value("KEPT_VARIABLE"), "Kept variable");
+ QCOMPARE(penv.value("CHANGED_VARIABLE"), "This variable will be changed");
+ QCOMPARE(penv.value("REMOVED_VARIABLE"), "Removed variable");
+}
+
void SetupDefaultQSettings()
{
QSettings::setDefaultFormat(QSettings::IniFormat);
diff --git a/Tests/CMakeGUI/CMakeGUITest.h b/Tests/CMakeGUI/CMakeGUITest.h
index 55a885b..891cf62 100644
--- a/Tests/CMakeGUI/CMakeGUITest.h
+++ b/Tests/CMakeGUI/CMakeGUITest.h
@@ -15,7 +15,12 @@ public:
private:
CMakeSetupDialog* m_window = nullptr;
+ void tryConfigure(int expectedResult = 0, int timeout = 60000);
+
private slots:
void sourceBinaryArgs();
void sourceBinaryArgs_data();
+ void simpleConfigure();
+ void simpleConfigure_data();
+ void environment();
};
diff --git a/Tests/CMakeGUI/CMakeLists.txt b/Tests/CMakeGUI/CMakeLists.txt
index 2a2ee1a..c6bc88a 100644
--- a/Tests/CMakeGUI/CMakeLists.txt
+++ b/Tests/CMakeGUI/CMakeLists.txt
@@ -10,13 +10,24 @@ include_directories(
set(MOC_SRCS)
qt5_wrap_cpp(MOC_SRCS
+ CatchShow.h
+ )
+add_library(CMakeGUITestLib STATIC ${MOC_SRCS}
+ CatchShow.cxx
+ CatchShow.h
+ )
+target_link_libraries(CMakeGUITestLib Qt5::Core Qt5::Gui Qt5::Widgets)
+
+set(MOC_SRCS)
+qt5_wrap_cpp(MOC_SRCS
CMakeGUITest.h
)
add_executable(CMakeGUITest CMakeGUITest.cxx ${MOC_SRCS})
-target_link_libraries(CMakeGUITest CMakeGUIMainLib Qt5::Core Qt5::Test Qt5::Widgets)
+target_link_libraries(CMakeGUITest CMakeGUIMainLib CMakeGUITestLib Qt5::Core Qt5::Test Qt5::Widgets)
target_compile_definitions(CMakeGUITest PRIVATE
"CMakeGUITest_SOURCE_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}\""
"CMakeGUITest_BINARY_DIR=\"${CMAKE_CURRENT_BINARY_DIR}\""
+ "CMAKE_GENERATOR=\"${CMAKE_GENERATOR}\""
)
add_test(NAME CMakeGUI COMMAND ${CMAKE_CMAKE_COMMAND}
@@ -35,11 +46,25 @@ function(add_cmake_gui_lib_test name)
${_t_MOC_SOURCES}
)
add_executable(${name} ${_t_SOURCES} ${MOC_SRCS})
- target_link_libraries(${name} CMakeGUILib Qt5::Core Qt5::Test Qt5::Widgets)
+ target_link_libraries(${name} CMakeGUILib CMakeGUITestLib Qt5::Core Qt5::Test Qt5::Widgets)
add_test(NAME "CMakeGUILib.${name}" COMMAND ${name})
endfunction()
+add_cmake_gui_lib_test(CatchShow
+ SOURCES
+ CatchShowTest.cxx
+ CatchShowTest.h
+ MOC_SOURCES
+ CatchShowTest.h
+ )
+add_cmake_gui_lib_test(EnvironmentDialog
+ SOURCES
+ EnvironmentDialogTest.cxx
+ EnvironmentDialogTest.h
+ MOC_SOURCES
+ EnvironmentDialogTest.h
+ )
add_cmake_gui_lib_test(QCMakeCacheModel
SOURCES
QCMakeCacheModelTest.cxx
diff --git a/Tests/CMakeGUI/CatchShow.cxx b/Tests/CMakeGUI/CatchShow.cxx
new file mode 100644
index 0000000..aee2d9d
--- /dev/null
+++ b/Tests/CMakeGUI/CatchShow.cxx
@@ -0,0 +1,25 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "CatchShow.h"
+
+#include <QCoreApplication>
+
+CatchShow::CatchShow(QObject* parent)
+ : QObject(parent)
+{
+ QCoreApplication::instance()->installEventFilter(this);
+}
+
+bool CatchShow::eventFilter(QObject* obj, QEvent* event)
+{
+ if (this->m_callback && event->type() == QEvent::Show) {
+ this->m_callback(obj);
+ }
+
+ return this->QObject::eventFilter(obj, event);
+}
+
+int CatchShow::count() const
+{
+ return this->m_count;
+}
diff --git a/Tests/CMakeGUI/CatchShow.h b/Tests/CMakeGUI/CatchShow.h
new file mode 100644
index 0000000..0254c15
--- /dev/null
+++ b/Tests/CMakeGUI/CatchShow.h
@@ -0,0 +1,41 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <functional>
+#include <memory>
+
+#include <QObject>
+#include <QWidget>
+
+class CatchShow : public QObject
+{
+ Q_OBJECT
+public:
+ CatchShow(QObject* parent = nullptr);
+
+ template <typename T, typename F>
+ void setCallback(F&& func);
+ bool eventFilter(QObject* obj, QEvent* event) override;
+ int count() const;
+
+private:
+ std::function<void(QObject* obj)> m_callback;
+ int m_count = 0;
+};
+
+template <typename T, typename F>
+void CatchShow::setCallback(F&& func)
+{
+ this->m_callback = [this, func](QObject* obj) {
+ auto* d = qobject_cast<T*>(obj);
+ if (d) {
+ QMetaObject::invokeMethod(obj,
+ [this, func, d]() {
+ ++this->m_count;
+ func(d);
+ },
+ Qt::QueuedConnection);
+ }
+ };
+}
diff --git a/Tests/CMakeGUI/CatchShowTest.cxx b/Tests/CMakeGUI/CatchShowTest.cxx
new file mode 100644
index 0000000..acea8ea
--- /dev/null
+++ b/Tests/CMakeGUI/CatchShowTest.cxx
@@ -0,0 +1,49 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "CatchShowTest.h"
+
+#include <QMessageBox>
+#include <QtTest>
+
+#include "CatchShow.h"
+
+CatchShowTest::CatchShowTest(QObject* parent)
+ : QObject(parent)
+{
+}
+
+void CatchShowTest::catchShow()
+{
+ bool have = false;
+ CatchShow catcher;
+ catcher.setCallback<QMessageBox>([&have](QMessageBox* box) {
+ have = true;
+ box->accept();
+ });
+
+ QCOMPARE(catcher.count(), 0);
+ QCOMPARE(have, false);
+
+ {
+ QDialog dialog;
+ dialog.show();
+ QCOMPARE(catcher.count(), 0);
+ QCOMPARE(have, false);
+ }
+
+ {
+ have = false;
+ QMessageBox::critical(nullptr, "Error", "This is an error");
+ QCOMPARE(catcher.count(), 1);
+ QCOMPARE(have, true);
+ }
+
+ {
+ have = false;
+ QMessageBox::information(nullptr, "Info", "This is information");
+ QCOMPARE(catcher.count(), 2);
+ QCOMPARE(have, true);
+ }
+}
+
+QTEST_MAIN(CatchShowTest)
diff --git a/Tests/CMakeGUI/CatchShowTest.h b/Tests/CMakeGUI/CatchShowTest.h
new file mode 100644
index 0000000..6da2163
--- /dev/null
+++ b/Tests/CMakeGUI/CatchShowTest.h
@@ -0,0 +1,15 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <QObject>
+
+class CatchShowTest : public QObject
+{
+ Q_OBJECT
+public:
+ CatchShowTest(QObject* parent = nullptr);
+
+private slots:
+ void catchShow();
+};
diff --git a/Tests/CMakeGUI/EnvironmentDialogTest.cxx b/Tests/CMakeGUI/EnvironmentDialogTest.cxx
new file mode 100644
index 0000000..9ec4996
--- /dev/null
+++ b/Tests/CMakeGUI/EnvironmentDialogTest.cxx
@@ -0,0 +1,142 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "EnvironmentDialogTest.h"
+
+#include <QDialogButtonBox>
+#include <QMessageBox>
+#include <QObject>
+#include <QPushButton>
+#include <QString>
+#include <QtTest>
+
+#include "CatchShow.h"
+#include "EnvironmentDialog.h"
+
+EnvironmentDialogTest::EnvironmentDialogTest(QObject* parent)
+ : QObject(parent)
+{
+}
+
+void EnvironmentDialogTest::environmentDialog()
+{
+ CatchShow catcher;
+ catcher.setCallback<QMessageBox>([](QMessageBox* box) { box->accept(); });
+
+ QProcessEnvironment env;
+ env.insert("DELETED_VARIABLE_1", "Deleted variable 1");
+ env.insert("DELETED_VARIABLE_2", "Deleted variable 2");
+ env.insert("KEPT_VARIABLE", "Kept variable");
+ env.insert("CHANGED_VARIABLE", "This will be changed");
+
+ EnvironmentDialog dialog(env);
+
+ {
+ QStringList expected{
+ "CHANGED_VARIABLE=This will be changed",
+ "DELETED_VARIABLE_1=Deleted variable 1",
+ "DELETED_VARIABLE_2=Deleted variable 2",
+ "KEPT_VARIABLE=Kept variable",
+ };
+ QCOMPARE(dialog.environment().toStringList(), expected);
+ QCOMPARE(catcher.count(), 0);
+ }
+
+ {
+ CatchShow catcher2;
+ bool done = false;
+ catcher2.setCallback<QDialog>([&catcher, &done](QDialog* box) {
+ if (done) {
+ return;
+ }
+ done = true;
+
+ auto name = box->findChild<QLineEdit*>("name");
+ auto value = box->findChild<QLineEdit*>("value");
+ auto acceptReject = box->findChild<QDialogButtonBox*>();
+
+ name->setText("");
+ value->setText("");
+ acceptReject->button(QDialogButtonBox::Ok)->click();
+ QCOMPARE(catcher.count(), 1);
+
+ name->setText("KEPT_VARIABLE");
+ value->setText("");
+ acceptReject->button(QDialogButtonBox::Ok)->click();
+ QCOMPARE(catcher.count(), 2);
+
+ name->setText("ADDED_VARIABLE");
+ value->setText("Added variable");
+ acceptReject->button(QDialogButtonBox::Ok)->click();
+ QCOMPARE(catcher.count(), 2);
+ });
+ dialog.AddEntry->click();
+
+ QStringList expected{
+ "ADDED_VARIABLE=Added variable",
+ "CHANGED_VARIABLE=This will be changed",
+ "DELETED_VARIABLE_1=Deleted variable 1",
+ "DELETED_VARIABLE_2=Deleted variable 2",
+ "KEPT_VARIABLE=Kept variable",
+ };
+ QCOMPARE(dialog.environment().toStringList(), expected);
+ QCOMPARE(catcher.count(), 2);
+ QVERIFY(done);
+ }
+
+ {
+ CatchShow catcher2;
+ bool done = false;
+ catcher2.setCallback<QDialog>([&done](QDialog* box) {
+ if (done) {
+ return;
+ }
+ done = true;
+
+ auto name = box->findChild<QLineEdit*>("name");
+ auto value = box->findChild<QLineEdit*>("value");
+ auto acceptReject = box->findChild<QDialogButtonBox*>();
+
+ name->setText("DISCARDED_VARIABLE");
+ value->setText("Discarded variable");
+ acceptReject->button(QDialogButtonBox::Cancel)->click();
+ });
+ dialog.AddEntry->click();
+
+ QStringList expected{
+ "ADDED_VARIABLE=Added variable",
+ "CHANGED_VARIABLE=This will be changed",
+ "DELETED_VARIABLE_1=Deleted variable 1",
+ "DELETED_VARIABLE_2=Deleted variable 2",
+ "KEPT_VARIABLE=Kept variable",
+ };
+ QCOMPARE(dialog.environment().toStringList(), expected);
+ QCOMPARE(catcher.count(), 2);
+ QVERIFY(done);
+ }
+
+ {
+ auto* model = dialog.Environment->model();
+ auto* selectionModel = dialog.Environment->selectionModel();
+ for (int i = 0; i < model->rowCount(); ++i) {
+ auto index1 = model->index(i, 0);
+ auto index2 = model->buddy(index1);
+ auto name = model->data(index1, Qt::DisplayRole).toString();
+ if (name == "DELETED_VARIABLE_1" || name == "DELETED_VARIABLE_2") {
+ selectionModel->select(index1, QItemSelectionModel::Select);
+ selectionModel->select(index2, QItemSelectionModel::Select);
+ } else if (name == "CHANGED_VARIABLE") {
+ model->setData(index2, "Changed variable", Qt::DisplayRole);
+ }
+ }
+ dialog.RemoveEntry->click();
+
+ QStringList expected{
+ "ADDED_VARIABLE=Added variable",
+ "CHANGED_VARIABLE=Changed variable",
+ "KEPT_VARIABLE=Kept variable",
+ };
+ QCOMPARE(dialog.environment().toStringList(), expected);
+ }
+}
+
+QTEST_MAIN(EnvironmentDialogTest)
diff --git a/Tests/CMakeGUI/EnvironmentDialogTest.h b/Tests/CMakeGUI/EnvironmentDialogTest.h
new file mode 100644
index 0000000..bcba2c5
--- /dev/null
+++ b/Tests/CMakeGUI/EnvironmentDialogTest.h
@@ -0,0 +1,15 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <QObject>
+
+class EnvironmentDialogTest : public QObject
+{
+ Q_OBJECT
+public:
+ EnvironmentDialogTest(QObject* parent = nullptr);
+
+private slots:
+ void environmentDialog();
+};
diff --git a/Tests/CMakeGUI/environment/CMakeLists.txt.in b/Tests/CMakeGUI/environment/CMakeLists.txt.in
new file mode 100644
index 0000000..1eeeb85
--- /dev/null
+++ b/Tests/CMakeGUI/environment/CMakeLists.txt.in
@@ -0,0 +1,18 @@
+cmake_minimum_required(VERSION 3.18)
+project(environment NONE)
+
+if(NOT "$ENV{KEPT_VARIABLE}" STREQUAL "Kept variable")
+ message(SEND_ERROR "KEPT_VARIABLE is \"$ENV{KEPT_VARIABLE}\", should be \"Kept variable\"")
+endif()
+
+if(NOT "$ENV{ADDED_VARIABLE}" STREQUAL "Added variable")
+ message(SEND_ERROR "ADDED_VARIABLE is \"$ENV{ADDED_VARIABLE}\", should be \"Added variable\"")
+endif()
+
+if(NOT "$ENV{CHANGED_VARIABLE}" STREQUAL "Changed variable")
+ message(SEND_ERROR "CHANGED_VARIABLE is \"$ENV{CHANGED_VARIABLE}\", should be \"Changed variable\"")
+endif()
+
+if(DEFINED ENV{REMOVED_VARIABLE})
+ message(SEND_ERROR "REMOVED_VARIABLE should not be defined")
+endif()
diff --git a/Tests/CMakeGUI/simpleConfigure-fail/CMakeLists.txt.in b/Tests/CMakeGUI/simpleConfigure-fail/CMakeLists.txt.in
new file mode 100644
index 0000000..dc55064
--- /dev/null
+++ b/Tests/CMakeGUI/simpleConfigure-fail/CMakeLists.txt.in
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 3.18)
+project(simpleConfigure-fail NONE)
+
+message(STATUS "This is a failed configure")
+message(FATAL_ERROR "Error")
diff --git a/Tests/CMakeGUI/simpleConfigure-success/CMakeLists.txt.in b/Tests/CMakeGUI/simpleConfigure-success/CMakeLists.txt.in
new file mode 100644
index 0000000..fc42c00
--- /dev/null
+++ b/Tests/CMakeGUI/simpleConfigure-success/CMakeLists.txt.in
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 3.18)
+project(simpleConfigure-success NONE)
+
+message(STATUS "This is a successful configure")
diff --git a/Tests/FindPython/CMakeLists.txt b/Tests/FindPython/CMakeLists.txt
index fdfa36e..44484c3 100644
--- a/Tests/FindPython/CMakeLists.txt
+++ b/Tests/FindPython/CMakeLists.txt
@@ -243,6 +243,87 @@ if(CMake_TEST_FindPython)
--test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
)
+ add_test(NAME FindPython.Python3.VersionRange.LOCATION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/VersionRange"
+ "${CMake_BINARY_DIR}/Tests/FindPython/Python3.VersionRange.LOCATION"
+ ${build_generator_args}
+ --build-project TestVersionRange
+ --build-options ${build_options} -DPython=Python3 -DPython_REQUESTED_VERSION=3
+ -DPython3_FIND_STRATEGY=LOCATION
+ )
+ add_test(NAME FindPython.Python3.VersionRange.VERSION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/VersionRange"
+ "${CMake_BINARY_DIR}/Tests/FindPython/Python3.VersionRange.VERSION"
+ ${build_generator_args}
+ --build-project TestVersionRange
+ --build-options ${build_options} -DPython=Python3 -DPython_REQUESTED_VERSION=3
+ -DPython3_FIND_STRATEGY=VERSION
+ )
+ add_test(NAME FindPython.Python2.VersionRange.LOCATION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/VersionRange"
+ "${CMake_BINARY_DIR}/Tests/FindPython/Python2.VersionRange.LOCATION"
+ ${build_generator_args}
+ --build-project TestVersionRange
+ --build-options ${build_options} -DPython=Python2 -DPython_REQUESTED_VERSION=2
+ -DPython2_FIND_STRATEGY=LOCATION
+ )
+ add_test(NAME FindPython.Python2.VersionRange.VERSION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/VersionRange"
+ "${CMake_BINARY_DIR}/Tests/FindPython/Python2.VersionRange.VERSION"
+ ${build_generator_args}
+ --build-project TestVersionRange
+ --build-options ${build_options} -DPython=Python2 -DPython_REQUESTED_VERSION=2
+ -DPython2_FIND_STRATEGY=VERSION
+ )
+ add_test(NAME FindPython.Python.V2.VersionRange.LOCATION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/VersionRange"
+ "${CMake_BINARY_DIR}/Tests/FindPython/Python.V2.VersionRange.LOCATION"
+ ${build_generator_args}
+ --build-project TestVersionRange
+ --build-options ${build_options} -DPython=Python -DPython_REQUESTED_VERSION=2
+ -DPython_FIND_STRATEGY=LOCATION
+ )
+ add_test(NAME FindPython.Python.V2.VersionRange.VERSION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/VersionRange"
+ "${CMake_BINARY_DIR}/Tests/FindPython/Python.V2.VersionRange.VERSION"
+ ${build_generator_args}
+ --build-project TestVersionRange
+ --build-options ${build_options} -DPython=Python -DPython_REQUESTED_VERSION=2
+ -DPython_FIND_STRATEGY=VERSION
+ )
+ add_test(NAME FindPython.Python.V3.VersionRange.LOCATION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/VersionRange"
+ "${CMake_BINARY_DIR}/Tests/FindPython/Python.V3.VersionRange.LOCATION"
+ ${build_generator_args}
+ --build-project TestVersionRange
+ --build-options ${build_options} -DPython=Python -DPython_REQUESTED_VERSION=3
+ -DPython_FIND_STRATEGY=LOCATION
+ )
+ add_test(NAME FindPython.Python.V3.VersionRange.VERSION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/VersionRange"
+ "${CMake_BINARY_DIR}/Tests/FindPython/Python.V3.VersionRange.VERSION"
+ ${build_generator_args}
+ --build-project TestVersionRange
+ --build-options ${build_options} -DPython=Python -DPython_REQUESTED_VERSION=3
+ -DPython_FIND_STRATEGY=VERSION
+ )
+
add_test(NAME FindPython.MultiplePackages COMMAND
${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
--build-and-test
@@ -492,6 +573,29 @@ if(CMake_TEST_FindPython_IronPython)
--build-options ${build_options} -DPython_REQUESTED_VERSION=2 -DPython_FIND_STRATEGY=VERSION
--test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
)
+
+ add_test(NAME FindPython.IronPython2.VersionRange.LOCATION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/VersionRange"
+ "${CMake_BINARY_DIR}/Tests/FindPython/IronPython2.VersionRange.LOCATION"
+ ${build_generator_args}
+ --build-project TestVersionRange
+ --build-options ${build_options} -DPython=Python2 -DPython_REQUESTED_VERSION=2
+ -DPython2_FIND_IMPLEMENTATIONS=IronPython
+ -DPython2_FIND_STRATEGY=LOCATION
+ )
+ add_test(NAME FindPython.IronPython2.VersionRange.VERSION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/VersionRange"
+ "${CMake_BINARY_DIR}/Tests/FindPython/IronPython2.VersionRange.VERSION"
+ ${build_generator_args}
+ --build-project TestVersionRange
+ --build-options ${build_options} -DPython=Python2 -DPython_REQUESTED_VERSION=2
+ -DPython2_FIND_IMPLEMENTATIONS=IronPython
+ -DPython2_FIND_STRATEGY=VERSION
+ )
endif()
if(CMake_TEST_FindPython_PyPy)
diff --git a/Tests/FindPython/VersionRange/CMakeLists.txt b/Tests/FindPython/VersionRange/CMakeLists.txt
new file mode 100644
index 0000000..0d946f5
--- /dev/null
+++ b/Tests/FindPython/VersionRange/CMakeLists.txt
@@ -0,0 +1,55 @@
+cmake_minimum_required (VERSION 3.18...3.19)
+
+project (TestVersionRange LANGUAGES NONE)
+
+
+find_package (${Python} ${Python_REQUESTED_VERSION} EXACT COMPONENTS Interpreter)
+if (NOT ${Python}_FOUND)
+ message (FATAL_ERROR "Failed to find ${Python} ${Python_REQUESTED_VERSION}")
+endif()
+
+if (Python_REQUESTED_VERSION VERSION_LESS 3.0)
+ set (IN_VERSION_RANGE 2.0...<3.0)
+ set (OUT_VERSION_RANGE 2.0...<${${Python}_VERSION})
+else()
+ set (IN_VERSION_RANGE 3.0...<4.0)
+ set (OUT_VERSION_RANGE 3.0...<${${Python}_VERSION})
+endif()
+
+function (FIND_PYTHON EXPECTED_VERSION)
+ unset (_${Python}_EXECUTABLE CACHE)
+ unset (_${Python}_LIBRARY_RELEASE CACHE)
+ unset (_${Python}_INCLUDE_DIR CACHE)
+ unset (${Python}_FOUND)
+
+ find_package (${ARGN})
+
+ if (EXPECTED_VERSION STREQUAL "NONE")
+ if (${Python}_FOUND)
+ message (SEND_ERROR "Unexpectedly found version: ${${Python}_VERSION} for ${ARGN}")
+ endif()
+ return()
+ endif()
+
+ if (NOT ${Python}_FOUND)
+ message (SEND_ERROR "Not found: ${ARGN}")
+ elseif (NOT ${Python}_VERSION VERSION_EQUAL EXPECTED_VERSION)
+ message (SEND_ERROR "Wrong version: ${${Python}_VERSION} for ${ARGN}")
+ endif()
+endfunction()
+
+find_python (${${Python}_VERSION} ${Python} ${IN_VERSION_RANGE} COMPONENTS Interpreter)
+if (${Python}_FIND_IMPLEMENTATIONS STREQUAL "IronPython")
+ find_python (${${Python}_VERSION} ${Python} ${IN_VERSION_RANGE} COMPONENTS Compiler)
+else()
+ find_python (${${Python}_VERSION} ${Python} ${IN_VERSION_RANGE} COMPONENTS Development)
+endif()
+
+find_python ("NONE" ${Python} ${OUT_VERSION_RANGE} COMPONENTS Interpreter)
+if (${Python}_FIND_IMPLEMENTATIONS STREQUAL "IronPython")
+ find_python ("NONE" ${Python} ${OUT_VERSION_RANGE} COMPONENTS Compiler)
+else()
+ find_python ("NONE" ${Python} ${OUT_VERSION_RANGE} COMPONENTS Development)
+endif()
+
+find_python ("NONE" ${Python} 5...6 COMPONENTS Interpreter)
diff --git a/Tests/IncludeDirectories/CMakeLists.txt b/Tests/IncludeDirectories/CMakeLists.txt
index eb08676..1f5b664 100644
--- a/Tests/IncludeDirectories/CMakeLists.txt
+++ b/Tests/IncludeDirectories/CMakeLists.txt
@@ -17,6 +17,7 @@ if (((CMAKE_C_COMPILER_ID STREQUAL GNU AND CMAKE_C_COMPILER_VERSION VERSION_GREA
endif()
if (run_sys_includes_test)
add_subdirectory(SystemIncludeDirectories)
+ add_subdirectory(SystemIncludeDirectoriesPerLang)
endif()
endif()
diff --git a/Tests/IncludeDirectories/SystemIncludeDirectoriesPerLang/CMakeLists.txt b/Tests/IncludeDirectories/SystemIncludeDirectoriesPerLang/CMakeLists.txt
new file mode 100644
index 0000000..70dfa01
--- /dev/null
+++ b/Tests/IncludeDirectories/SystemIncludeDirectoriesPerLang/CMakeLists.txt
@@ -0,0 +1,23 @@
+cmake_minimum_required(VERSION 3.17 FATAL_ERROR)
+
+project(SystemIncludeDirectoriesPerLang)
+
+add_library(c_interface INTERFACE)
+set_target_properties(c_interface PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "$<$<COMPILE_LANGUAGE:C>:${CMAKE_CURRENT_SOURCE_DIR}>"
+ INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "$<$<COMPILE_LANGUAGE:C>:${CMAKE_CURRENT_SOURCE_DIR}>"
+)
+target_compile_options(c_interface INTERFACE "$<$<COMPILE_LANG_AND_ID:C,GNU,Clang>:-Werror=unused-variable>")
+
+add_library(cxx_interface INTERFACE)
+set_target_properties(cxx_interface PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "$<$<COMPILE_LANGUAGE:CXX>:${CMAKE_CURRENT_SOURCE_DIR}/cxx_system_include>"
+ INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "$<$<COMPILE_LANGUAGE:CXX>:${CMAKE_CURRENT_SOURCE_DIR}/cxx_system_include>"
+)
+target_compile_options(cxx_interface INTERFACE "$<$<COMPILE_LANG_AND_ID:CXX,GNU,Clang>:-Werror=unused-variable>")
+
+# The C header must come before the C++ header for this test to smoke out the
+# failure. The order of sources is how CMake determines the include cache
+# and we need it to cache on the 'bad' language first
+add_executable(consume_multi_lang_includes main.c smoke_out_includes.cxx)
+target_link_libraries(consume_multi_lang_includes PRIVATE c_interface cxx_interface)
diff --git a/Tests/IncludeDirectories/SystemIncludeDirectoriesPerLang/cxx_system_include/header.h b/Tests/IncludeDirectories/SystemIncludeDirectoriesPerLang/cxx_system_include/header.h
new file mode 100644
index 0000000..8dcd226
--- /dev/null
+++ b/Tests/IncludeDirectories/SystemIncludeDirectoriesPerLang/cxx_system_include/header.h
@@ -0,0 +1,10 @@
+
+// Generate a warning in here
+
+int function_that_generates_warning(int x)
+{
+ int y = x;
+ int z = 2;
+ y -= x;
+ return y;
+}
diff --git a/Tests/IncludeDirectories/SystemIncludeDirectoriesPerLang/main.c b/Tests/IncludeDirectories/SystemIncludeDirectoriesPerLang/main.c
new file mode 100644
index 0000000..f8b643a
--- /dev/null
+++ b/Tests/IncludeDirectories/SystemIncludeDirectoriesPerLang/main.c
@@ -0,0 +1,4 @@
+int main()
+{
+ return 0;
+}
diff --git a/Tests/IncludeDirectories/SystemIncludeDirectoriesPerLang/smoke_out_includes.cxx b/Tests/IncludeDirectories/SystemIncludeDirectoriesPerLang/smoke_out_includes.cxx
new file mode 100644
index 0000000..dbfc557
--- /dev/null
+++ b/Tests/IncludeDirectories/SystemIncludeDirectoriesPerLang/smoke_out_includes.cxx
@@ -0,0 +1,7 @@
+
+#include <header.h>
+
+int empty_func()
+{
+ return function_that_generates_warning(4);
+}
diff --git a/Tests/ObjCXX/CMakeLists.txt b/Tests/ObjCXX/CMakeLists.txt
index a2a907a..cf03771 100644
--- a/Tests/ObjCXX/CMakeLists.txt
+++ b/Tests/ObjCXX/CMakeLists.txt
@@ -2,3 +2,4 @@ ADD_TEST_MACRO(ObjCXX.ObjC++ ObjC++)
ADD_TEST_MACRO(ObjCXX.simple-build-test simple-build-test)
ADD_TEST_MACRO(ObjCXX.cxx-file-extension-test cxx-file-extension-test)
ADD_TEST_MACRO(ObjCXX.objcxx-file-extension-test objcxx-file-extension-test)
+ADD_TEST_MACRO(ObjCXX.cxx-as-objcxx cxx-as-objcxx)
diff --git a/Tests/ObjCXX/cxx-as-objcxx/CMakeLists.txt b/Tests/ObjCXX/cxx-as-objcxx/CMakeLists.txt
new file mode 100644
index 0000000..23f6891
--- /dev/null
+++ b/Tests/ObjCXX/cxx-as-objcxx/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 3.18)
+project(cxx-as-objcxx LANGUAGES OBJCXX)
+
+add_executable(cxx-as-objcxx main.cpp)
+set_source_files_properties(main.cpp PROPERTIES LANGUAGE OBJCXX)
diff --git a/Tests/ObjCXX/cxx-as-objcxx/main.cpp b/Tests/ObjCXX/cxx-as-objcxx/main.cpp
new file mode 100644
index 0000000..701c567
--- /dev/null
+++ b/Tests/ObjCXX/cxx-as-objcxx/main.cpp
@@ -0,0 +1,6 @@
+#import <Foundation/Foundation.h>
+
+int main(int argc, char* argv[])
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index c97a959..c70eb75 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -311,7 +311,11 @@ add_RunCMake_test(cmake_parse_arguments)
add_RunCMake_test(cmake_path)
add_RunCMake_test(continue)
add_executable(color_warning color_warning.c)
-add_RunCMake_test(ctest_build -DCOLOR_WARNING=$<TARGET_FILE:color_warning>)
+add_executable(fake_build_command fake_build_command.c)
+add_RunCMake_test(ctest_build
+ -DCOLOR_WARNING=$<TARGET_FILE:color_warning>
+ -DFAKE_BUILD_COMMAND_EXE=$<TARGET_FILE:fake_build_command>
+)
add_RunCMake_test(ctest_cmake_error)
add_RunCMake_test(ctest_configure)
if(COVERAGE_COMMAND)
diff --git a/Tests/RunCMake/CommandLine/trace-json-v1-check.py b/Tests/RunCMake/CommandLine/trace-json-v1-check.py
index e617b76..1ee005e 100755
--- a/Tests/RunCMake/CommandLine/trace-json-v1-check.py
+++ b/Tests/RunCMake/CommandLine/trace-json-v1-check.py
@@ -56,7 +56,7 @@ with open(trace_file, 'r') as fp:
assert sorted(vers.keys()) == ['version']
assert sorted(vers['version'].keys()) == ['major', 'minor']
assert vers['version']['major'] == 1
- assert vers['version']['minor'] == 0
+ assert vers['version']['minor'] == 1
for i in fp.readlines():
line = json.loads(i)
diff --git a/Tests/RunCMake/FPHSA/RunCMakeTest.cmake b/Tests/RunCMake/FPHSA/RunCMakeTest.cmake
index e4b8700..28b8570 100644
--- a/Tests/RunCMake/FPHSA/RunCMakeTest.cmake
+++ b/Tests/RunCMake/FPHSA/RunCMakeTest.cmake
@@ -61,8 +61,6 @@ set(RunCMake_TEST_OPTIONS "-DCMAKE_MODULE_PATH=${CMAKE_CURRENT_LIST_DIR}" "-DPse
run_cmake(range_ignored)
set(RunCMake_TEST_OPTIONS "-DCMAKE_MODULE_PATH=${CMAKE_CURRENT_LIST_DIR}" "-DPseudoRange_VERSION=2.0")
run_cmake(range_no-range)
-run_cmake(range_empty-1)
-run_cmake(range_empty-2)
run_cmake(range_1-3)
run_cmake(range_1-2-include)
run_cmake(range_1-2-exclude)
diff --git a/Tests/RunCMake/FPHSA/range_empty-1-stderr.txt b/Tests/RunCMake/FPHSA/range_empty-1-stderr.txt
deleted file mode 100644
index e1c741a..0000000
--- a/Tests/RunCMake/FPHSA/range_empty-1-stderr.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-CMake Error at .+FindPackageHandleStandardArgs.cmake:[0-9]+ \(message\):
- Could NOT find PseudoRange: Found unsuitable version "2\.0", required range
- is empty \("3\.0\.\.\.2\.0"\) \(found TRUE\)
-Call Stack \(most recent call first\):
- .+FindPackageHandleStandardArgs.cmake:[0-9]+ \(_FPHSA_FAILURE_MESSAGE\)
- FindPseudoRange.cmake:[0-9]+ \(find_package_handle_standard_args\)
diff --git a/Tests/RunCMake/FPHSA/range_empty-1.cmake b/Tests/RunCMake/FPHSA/range_empty-1.cmake
deleted file mode 100644
index c510d7d..0000000
--- a/Tests/RunCMake/FPHSA/range_empty-1.cmake
+++ /dev/null
@@ -1 +0,0 @@
-find_package(PseudoRange 3.0...2.0 REQUIRED)
diff --git a/Tests/RunCMake/FPHSA/range_empty-2-stderr.txt b/Tests/RunCMake/FPHSA/range_empty-2-stderr.txt
deleted file mode 100644
index ee0e79a..0000000
--- a/Tests/RunCMake/FPHSA/range_empty-2-stderr.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-CMake Error at .+FindPackageHandleStandardArgs.cmake:[0-9]+ \(message\):
- Could NOT find PseudoRange: Found unsuitable version "2\.0", required range
- is empty \("2\.0\.\.\.<2.0"\) \(found TRUE\)
-Call Stack \(most recent call first\):
- .+FindPackageHandleStandardArgs.cmake:[0-9]+ \(_FPHSA_FAILURE_MESSAGE\)
- FindPseudoRange.cmake:[0-9]+ \(find_package_handle_standard_args\)
diff --git a/Tests/RunCMake/FPHSA/range_empty-2.cmake b/Tests/RunCMake/FPHSA/range_empty-2.cmake
deleted file mode 100644
index 3ce90e8..0000000
--- a/Tests/RunCMake/FPHSA/range_empty-2.cmake
+++ /dev/null
@@ -1 +0,0 @@
-find_package(PseudoRange 2.0...<2.0 REQUIRED)
diff --git a/Tests/RunCMake/VS10Project/LanguageStandard-check.cmake b/Tests/RunCMake/VS10Project/LanguageStandard-check.cmake
new file mode 100644
index 0000000..85e2858
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/LanguageStandard-check.cmake
@@ -0,0 +1,23 @@
+set(vcProjectFile "${RunCMake_TEST_BINARY_DIR}/foo.vcxproj")
+if(NOT EXISTS "${vcProjectFile}")
+ set(RunCMake_TEST_FAILED "Project file ${vcProjectFile} does not exist.")
+ return()
+endif()
+
+set(found_LanguageStandard_stdcpp17 0)
+set(found_LanguageStandard_C_stdc11 0)
+file(STRINGS "${vcProjectFile}" lines)
+foreach(line IN LISTS lines)
+ if(line MATCHES "<LanguageStandard>stdcpp17</LanguageStandard>")
+ set(found_LanguageStandard_stdcpp17 1)
+ endif()
+ if(line MATCHES "<LanguageStandard_C>stdc11</LanguageStandard_C>")
+ set(found_LanguageStandard_C_stdc11 1)
+ endif()
+endforeach()
+if(NOT found_LanguageStandard_stdcpp17)
+ string(APPEND RunCMake_TEST_FAILED "LanguageStandard stdcpp17 not found in\n ${vcProjectFile}\n")
+endif()
+if(NOT found_LanguageStandard_C_stdc11)
+ string(APPEND RunCMake_TEST_FAILED "LanguageStandard_C stdc11 not found in\n ${vcProjectFile}\n")
+endif()
diff --git a/Tests/RunCMake/VS10Project/LanguageStandard.cmake b/Tests/RunCMake/VS10Project/LanguageStandard.cmake
new file mode 100644
index 0000000..f8b62e2
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/LanguageStandard.cmake
@@ -0,0 +1,5 @@
+enable_language(C)
+enable_language(CXX)
+
+add_library(foo empty.c empty.cxx)
+target_compile_features(foo PRIVATE c_std_11 cxx_std_17)
diff --git a/Tests/RunCMake/VS10Project/NoImpLib-check.cmake b/Tests/RunCMake/VS10Project/NoImpLib-check.cmake
new file mode 100644
index 0000000..50722b2
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/NoImpLib-check.cmake
@@ -0,0 +1,23 @@
+set(vcProjectFile "${RunCMake_TEST_BINARY_DIR}/foo.vcxproj")
+if(NOT EXISTS "${vcProjectFile}")
+ set(RunCMake_TEST_FAILED "Project file ${vcProjectFile} does not exist.")
+ return()
+endif()
+
+set(found_ImportLibrary 0)
+set(found_TargetExt_dll 0)
+file(STRINGS "${vcProjectFile}" lines)
+foreach(line IN LISTS lines)
+ if(line MATCHES "<ImportLibrary>")
+ set(found_ImportLibrary 1)
+ endif()
+ if(line MATCHES "<TargetExt[^\n]*\\.dll")
+ set(found_TargetExt_dll 1)
+ endif()
+endforeach()
+if(found_ImportLibrary)
+ string(APPEND RunCMake_TEST_FAILED "ImportLibrary incorrectly found in\n ${vcProjectFile}\n")
+endif()
+if(NOT found_TargetExt_dll)
+ string(APPEND RunCMake_TEST_FAILED "TargetExt not found in\n ${vcProjectFile}\n")
+endif()
diff --git a/Tests/RunCMake/VS10Project/NoImpLib.cmake b/Tests/RunCMake/VS10Project/NoImpLib.cmake
new file mode 100644
index 0000000..2c11eac
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/NoImpLib.cmake
@@ -0,0 +1,3 @@
+enable_language(C)
+set(CMAKE_IMPORT_LIBRARY_SUFFIX "")
+add_library(foo SHARED empty.c)
diff --git a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake
index e9f251a..133dacc 100644
--- a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake
+++ b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake
@@ -3,10 +3,15 @@ cmake_policy(SET CMP0057 NEW)
include(RunCMake)
cmake_policy(SET CMP0054 NEW)
+if(CMAKE_C_COMPILER_ID STREQUAL "MSVC" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 19.27)
+ run_cmake(LanguageStandard)
+endif()
+
run_cmake(VsCsharpSourceGroup)
run_cmake(VsCSharpCompilerOpts)
run_cmake(ExplicitCMakeLists)
run_cmake(InterfaceLibSources)
+run_cmake(NoImpLib)
run_cmake(RuntimeLibrary)
run_cmake(SourceGroupCMakeLists)
run_cmake(SourceGroupTreeCMakeLists)
diff --git a/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake b/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake
index 34fc26e..62163ac 100644
--- a/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake
+++ b/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake
@@ -108,11 +108,6 @@ XcodeRemoveExcessiveISystem()
# Isolate device tests from host architecture selection.
unset(ENV{CMAKE_OSX_ARCHITECTURES})
-if(XCODE_VERSION VERSION_GREATER_EQUAL 12)
- # FIXME: Restore device tests and fix them for the Xcode "new build system"
- return()
-endif()
-
# Use a single build tree for a few tests without cleaning.
if(NOT XCODE_VERSION VERSION_LESS 5)
@@ -142,8 +137,8 @@ if(NOT XCODE_VERSION VERSION_LESS 5)
file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
run_cmake(XcodeBundles)
- run_cmake_command(XcodeBundles-build ${CMAKE_COMMAND} --build .)
- run_cmake_command(XcodeBundles-install ${CMAKE_COMMAND} --build . --target install)
+ run_cmake_command(XcodeBundles-build-macOS ${CMAKE_COMMAND} --build .)
+ run_cmake_command(XcodeBundles-install-macOS ${CMAKE_COMMAND} --build . --target install)
unset(RunCMake_TEST_BINARY_DIR)
unset(RunCMake_TEST_NO_CLEAN)
@@ -159,8 +154,8 @@ if(NOT XCODE_VERSION VERSION_LESS 5)
file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
run_cmake(XcodeBundles)
- run_cmake_command(XcodeBundles-build ${CMAKE_COMMAND} --build .)
- run_cmake_command(XcodeBundles-install ${CMAKE_COMMAND} --build . --target install)
+ run_cmake_command(XcodeBundles-build-iOS ${CMAKE_COMMAND} --build .)
+ run_cmake_command(XcodeBundles-install-iOS ${CMAKE_COMMAND} --build . --target install)
unset(RunCMake_TEST_BINARY_DIR)
unset(RunCMake_TEST_NO_CLEAN)
@@ -178,8 +173,8 @@ if(NOT XCODE_VERSION VERSION_LESS 7)
file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
run_cmake(XcodeBundles)
- run_cmake_command(XcodeBundles-build ${CMAKE_COMMAND} --build .)
- run_cmake_command(XcodeBundles-install ${CMAKE_COMMAND} --build . --target install)
+ run_cmake_command(XcodeBundles-build-watchOS ${CMAKE_COMMAND} --build .)
+ run_cmake_command(XcodeBundles-install-watchOS ${CMAKE_COMMAND} --build . --target install)
unset(RunCMake_TEST_BINARY_DIR)
unset(RunCMake_TEST_NO_CLEAN)
@@ -197,8 +192,8 @@ if(NOT XCODE_VERSION VERSION_LESS 7.1)
file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
run_cmake(XcodeBundles)
- run_cmake_command(XcodeBundles-build ${CMAKE_COMMAND} --build .)
- run_cmake_command(XcodeBundles-install ${CMAKE_COMMAND} --build . --target install)
+ run_cmake_command(XcodeBundles-build-tvOS ${CMAKE_COMMAND} --build .)
+ run_cmake_command(XcodeBundles-install-tvOS ${CMAKE_COMMAND} --build . --target install)
unset(RunCMake_TEST_BINARY_DIR)
unset(RunCMake_TEST_NO_CLEAN)
@@ -211,7 +206,7 @@ if(NOT XCODE_VERSION VERSION_LESS 7)
unset(RunCMake_TEST_OPTIONS)
endif()
-if(NOT XCODE_VERSION VERSION_LESS 6)
+if(XCODE_VERSION VERSION_GREATER_EQUAL 6 AND XCODE_VERSION VERSION_LESS 12)
# XcodeIOSInstallCombined
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/XcodeIOSInstallCombined-build)
set(RunCMake_TEST_NO_CLEAN 1)
diff --git a/Tests/RunCMake/cmake_language/CallInvalidCommand.cmake b/Tests/RunCMake/cmake_language/CallInvalidCommand.cmake
deleted file mode 100644
index 8bee6f2..0000000
--- a/Tests/RunCMake/cmake_language/CallInvalidCommand.cmake
+++ /dev/null
@@ -1,2 +0,0 @@
-
-cmake_language(CALL ${COMMAND})
diff --git a/Tests/RunCMake/cmake_language/RunCMakeTest.cmake b/Tests/RunCMake/cmake_language/RunCMakeTest.cmake
index 5fb93c8..6480b2e 100644
--- a/Tests/RunCMake/cmake_language/RunCMakeTest.cmake
+++ b/Tests/RunCMake/cmake_language/RunCMakeTest.cmake
@@ -2,7 +2,16 @@ include(RunCMake)
run_cmake(no_parameters)
run_cmake(unknown_meta_operation)
-run_cmake(call_invalid_command)
+foreach(command IN ITEMS
+ "function" "ENDFUNCTION"
+ "macro" "endMACRO"
+ "if" "elseif" "else" "endif"
+ "while" "endwhile"
+ "foreach" "endforeach"
+ )
+ message(STATUS "Running call_invalid_command for ${command}...")
+ run_cmake_with_options(call_invalid_command -Dcommand=${command})
+endforeach()
run_cmake(call_valid_command)
run_cmake(call_double_evaluation)
run_cmake(call_expanded_command)
@@ -23,3 +32,53 @@ run_cmake(eval_message_fatal_error)
run_cmake(eval_no_code)
run_cmake(eval_no_parameters)
run_cmake(eval_variable_outside_message)
+run_cmake(defer_call)
+run_cmake(defer_call_add_subdirectory)
+run_cmake(defer_call_enable_language)
+run_cmake(defer_call_ids)
+foreach(command IN ITEMS
+ "function" "endfunction"
+ "macro" "endmacro"
+ "if" "elseif" "else" "endif"
+ "while" "endwhile"
+ "foreach" "endforeach"
+ "return"
+ )
+ message(STATUS "Running defer_call_invalid_command for ${command}...")
+ run_cmake_with_options(defer_call_invalid_command -Dcommand=${command})
+endforeach()
+run_cmake(defer_call_invalid_directory)
+run_cmake(defer_call_error)
+run_cmake(defer_call_missing_directory)
+run_cmake(defer_call_policy_PUSH)
+run_cmake(defer_call_syntax_error)
+run_cmake_with_options(defer_call_trace --trace-expand)
+run_cmake_with_options(defer_call_trace_json --trace --trace-format=json-v1)
+run_cmake(defer_cancel_call_unknown_argument)
+run_cmake(defer_cancel_call_invalid_directory)
+run_cmake(defer_cancel_call_id)
+run_cmake(defer_cancel_call_id_var)
+run_cmake(defer_directory_empty)
+run_cmake(defer_directory_missing)
+run_cmake(defer_directory_multiple)
+run_cmake(defer_id_empty)
+run_cmake(defer_id_missing)
+run_cmake(defer_id_multiple)
+run_cmake(defer_id_var_empty)
+run_cmake(defer_id_var_missing)
+run_cmake(defer_id_var_multiple)
+run_cmake(defer_get_call_ids_missing_var)
+run_cmake(defer_get_call_ids_too_many_args)
+run_cmake(defer_get_call_ids_invalid_directory)
+run_cmake(defer_get_call_ids_id)
+run_cmake(defer_get_call_ids_id_var)
+run_cmake(defer_get_call_missing_id)
+run_cmake(defer_get_call_missing_var)
+run_cmake(defer_get_call_too_many_args)
+run_cmake(defer_get_call_id_empty)
+run_cmake(defer_get_call_unknown_argument)
+run_cmake(defer_get_call_id)
+run_cmake(defer_get_call_id_var)
+run_cmake(defer_missing_arg)
+run_cmake(defer_missing_call)
+run_cmake(defer_unknown_option)
diff --git a/Tests/RunCMake/cmake_language/call_expand_command_name.cmake b/Tests/RunCMake/cmake_language/call_expand_command_name.cmake
index e03bb1f..f74d303 100644
--- a/Tests/RunCMake/cmake_language/call_expand_command_name.cmake
+++ b/Tests/RunCMake/cmake_language/call_expand_command_name.cmake
@@ -1,2 +1,2 @@
set (my_call "CALL")
-cmake_language (${my_call} message "OK!")
+cmake_language (${my_call} ${empty} message "OK!")
diff --git a/Tests/RunCMake/cmake_language/call_expanded_command.cmake b/Tests/RunCMake/cmake_language/call_expanded_command.cmake
index e76e612..c52468d 100644
--- a/Tests/RunCMake/cmake_language/call_expanded_command.cmake
+++ b/Tests/RunCMake/cmake_language/call_expanded_command.cmake
@@ -3,4 +3,4 @@ function (itsok)
endfunction()
set (cmd CALL itsok)
-cmake_language (${cmd})
+cmake_language (${empty} ${cmd})
diff --git a/Tests/RunCMake/cmake_language/call_expanded_command_and_arguments-stderr.txt b/Tests/RunCMake/cmake_language/call_expanded_command_and_arguments-stderr.txt
index e87e9bc..82411d2 100644
--- a/Tests/RunCMake/cmake_language/call_expanded_command_and_arguments-stderr.txt
+++ b/Tests/RunCMake/cmake_language/call_expanded_command_and_arguments-stderr.txt
@@ -1,4 +1,4 @@
CMake Error at call_expanded_command_and_arguments.cmake:2 \(cmake_language\):
- cmake_language called with incorrect number of arguments
+ cmake_language CALL command's arguments must be literal
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/FPHSA/range_empty-2-result.txt b/Tests/RunCMake/cmake_language/call_invalid_command-result.txt
index d00491f..d00491f 100644
--- a/Tests/RunCMake/FPHSA/range_empty-2-result.txt
+++ b/Tests/RunCMake/cmake_language/call_invalid_command-result.txt
diff --git a/Tests/RunCMake/cmake_language/call_invalid_command-stderr.txt b/Tests/RunCMake/cmake_language/call_invalid_command-stderr.txt
new file mode 100644
index 0000000..4439842
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/call_invalid_command-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at call_invalid_command.cmake:1 \(cmake_language\):
+ cmake_language invalid command specified: [A-Za-z_]+
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/cmake_language/call_invalid_command.cmake b/Tests/RunCMake/cmake_language/call_invalid_command.cmake
index 585aad4..f213895 100644
--- a/Tests/RunCMake/cmake_language/call_invalid_command.cmake
+++ b/Tests/RunCMake/cmake_language/call_invalid_command.cmake
@@ -1,14 +1 @@
-
-foreach (command IN ITEMS "function" "ENDFUNCTION"
- "macro" "endMACRO"
- "if" "elseif" "else" "endif"
- "while" "endwhile"
- "foreach" "endforeach")
- execute_process(COMMAND "${CMAKE_COMMAND}" -DCOMMAND=${command}
- -P "${CMAKE_CURRENT_SOURCE_DIR}/CallInvalidCommand.cmake"
- OUTPUT_QUIET ERROR_QUIET
- RESULT_VARIABLE result)
- if (NOT result)
- message (SEND_ERROR "cmake_language(CALL ${command}) unexpectedly successful.")
- endif()
-endforeach()
+cmake_language(CALL ${command})
diff --git a/Tests/RunCMake/cmake_language/call_message.cmake b/Tests/RunCMake/cmake_language/call_message.cmake
index 31aefdf..3b98c80 100644
--- a/Tests/RunCMake/cmake_language/call_message.cmake
+++ b/Tests/RunCMake/cmake_language/call_message.cmake
@@ -1 +1 @@
-cmake_language(CALL message WORKS!)
+cmake_language(CALL ${empty} message WORKS!)
diff --git a/Tests/RunCMake/cmake_language/call_no_parameters-stderr.txt b/Tests/RunCMake/cmake_language/call_no_parameters-stderr.txt
index 9e2c08f..f6a0458 100644
--- a/Tests/RunCMake/cmake_language/call_no_parameters-stderr.txt
+++ b/Tests/RunCMake/cmake_language/call_no_parameters-stderr.txt
@@ -1,2 +1,2 @@
CMake Error at call_no_parameters.cmake:1 \(cmake_language\):
- cmake_language called with incorrect number of arguments
+ cmake_language CALL missing command name
diff --git a/Tests/RunCMake/cmake_language/defer_call-stderr.txt b/Tests/RunCMake/cmake_language/defer_call-stderr.txt
new file mode 100644
index 0000000..7e8d8ca
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_call-stderr.txt
@@ -0,0 +1,15 @@
+^CMake Deprecation Warning at defer_call/CMakeLists.txt:[0-9]+ \(cmake_policy\):
+ The OLD behavior for policy CMP0053 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
++
+CMake Warning at defer_call/CMakeLists.txt:3 \(message\):
+ Double-Deferred Warning In Subdirectory:
+
+ '[^']*/Tests/RunCMake/cmake_language/defer_call/CMakeLists.txt:DEFERRED:id3'
+Call Stack \(most recent call first\):
+ defer_call/CMakeLists.txt:DEFERRED$
diff --git a/Tests/RunCMake/cmake_language/defer_call-stdout.txt b/Tests/RunCMake/cmake_language/defer_call-stdout.txt
new file mode 100644
index 0000000..fcf9f29
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_call-stdout.txt
@@ -0,0 +1,8 @@
+-- Immediate Message In Subdirectory: ids='__0;__1'
+-- Deferred Message In Subdirectory: '[^']*/Tests/RunCMake/cmake_language/defer_call/CMakeLists.txt:DEFERRED:id1'
+-- Deferred Message In Included File: '[^']*/Tests/RunCMake/cmake_language/defer_call/include.cmake:1'
+-- Immediate Message: ids='__0;__1;__2;__3;__4'
+-- First Deferred Message
+-- Deferred Message From Subdirectory
+-- Deferred Message: ids='__4;__5'
+-- Final Deferred Message
diff --git a/Tests/RunCMake/cmake_language/defer_call.cmake b/Tests/RunCMake/cmake_language/defer_call.cmake
new file mode 100644
index 0000000..2e9595f
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_call.cmake
@@ -0,0 +1,12 @@
+set(message_command "message")
+set(final_message "This should not be printed because variable evaluation is deferred too.")
+cmake_language(DEFER CALL ${message_command} STATUS "First Deferred Message")
+add_subdirectory(defer_call)
+cmake_language(DEFER CALL cmake_language DEFER CALL "${final_message_command}" STATUS "${final_message}")
+cmake_language(DEFER CALL cmake_language DEFER GET_CALL_IDS ids)
+cmake_language(DEFER CALL cmake_language EVAL CODE [[message(STATUS "Deferred Message: ids='${ids}'")]])
+cmake_language(DEFER GET_CALL_IDS ids)
+message(STATUS "Immediate Message: ids='${ids}'")
+set(final_message_command "message")
+set(final_message "Final Deferred Message")
+set(subdir_message "Deferred Message From Subdirectory")
diff --git a/Tests/RunCMake/cmake_language/defer_call/CMakeLists.txt b/Tests/RunCMake/cmake_language/defer_call/CMakeLists.txt
new file mode 100644
index 0000000..544b9f4
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_call/CMakeLists.txt
@@ -0,0 +1,11 @@
+cmake_policy(SET CMP0053 OLD)
+cmake_language(DEFER ID id1 CALL message STATUS "Deferred Message In Subdirectory: '${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE}'")
+cmake_language(DEFER ID id2 CALL
+ cmake_language DEFER ID id3 CALL
+ message WARNING "Double-Deferred Warning In Subdirectory:\n '${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE}'")
+cmake_language(DEFER ID id4 CALL include "${CMAKE_CURRENT_LIST_DIR}/include.cmake")
+
+set(subdir_message "This should not be printed because variable evaluation is in deferred scope.")
+cmake_language(DEFER DIRECTORY .. CALL message STATUS "${subdir_message}")
+cmake_language(DEFER DIRECTORY .. GET_CALL_IDS ids)
+message(STATUS "Immediate Message In Subdirectory: ids='${ids}'")
diff --git a/Tests/RunCMake/cmake_language/defer_call/include.cmake b/Tests/RunCMake/cmake_language/defer_call/include.cmake
new file mode 100644
index 0000000..272c61b
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_call/include.cmake
@@ -0,0 +1 @@
+message(STATUS "Deferred Message In Included File: '${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE}'")
diff --git a/Tests/RunCMake/FPHSA/range_empty-1-result.txt b/Tests/RunCMake/cmake_language/defer_call_add_subdirectory-result.txt
index d00491f..d00491f 100644
--- a/Tests/RunCMake/FPHSA/range_empty-1-result.txt
+++ b/Tests/RunCMake/cmake_language/defer_call_add_subdirectory-result.txt
diff --git a/Tests/RunCMake/cmake_language/defer_call_add_subdirectory-stderr.txt b/Tests/RunCMake/cmake_language/defer_call_add_subdirectory-stderr.txt
new file mode 100644
index 0000000..ec20b8f
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_call_add_subdirectory-stderr.txt
@@ -0,0 +1,9 @@
+^CMake Error at defer_call_add_subdirectory.cmake:1 \(add_subdirectory\):
+ Subdirectories may not be created during deferred execution.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:DEFERRED
++
+CMake Error at defer_call_add_subdirectory.cmake:2 \(subdirs\):
+ Subdirectories may not be created during deferred execution.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:DEFERRED$
diff --git a/Tests/RunCMake/cmake_language/defer_call_add_subdirectory.cmake b/Tests/RunCMake/cmake_language/defer_call_add_subdirectory.cmake
new file mode 100644
index 0000000..6b7ee63
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_call_add_subdirectory.cmake
@@ -0,0 +1,2 @@
+cmake_language(DEFER CALL add_subdirectory defer_call_add_subdirectory)
+cmake_language(DEFER CALL subdirs defer_call_add_subdirectory)
diff --git a/Tests/RunCMake/cmake_language/defer_call_add_subdirectory/CMakeLists.txt b/Tests/RunCMake/cmake_language/defer_call_add_subdirectory/CMakeLists.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_call_add_subdirectory/CMakeLists.txt
diff --git a/Tests/RunCMake/cmake_language/defer_call_enable_language-result.txt b/Tests/RunCMake/cmake_language/defer_call_enable_language-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_call_enable_language-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_language/defer_call_enable_language-stderr.txt b/Tests/RunCMake/cmake_language/defer_call_enable_language-stderr.txt
new file mode 100644
index 0000000..65a0b99
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_call_enable_language-stderr.txt
@@ -0,0 +1,9 @@
+^CMake Error at defer_call_enable_language.cmake:1 \(enable_language\):
+ Languages may not be enabled during deferred execution.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:DEFERRED
++
+CMake Error at defer_call_enable_language.cmake:2 \(project\):
+ Languages may not be enabled during deferred execution.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:DEFERRED$
diff --git a/Tests/RunCMake/cmake_language/defer_call_enable_language.cmake b/Tests/RunCMake/cmake_language/defer_call_enable_language.cmake
new file mode 100644
index 0000000..eb43f80
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_call_enable_language.cmake
@@ -0,0 +1,2 @@
+cmake_language(DEFER CALL enable_language C)
+cmake_language(DEFER CALL project foo C)
diff --git a/Tests/RunCMake/cmake_language/defer_call_error-result.txt b/Tests/RunCMake/cmake_language/defer_call_error-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_call_error-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_language/defer_call_error-stderr.txt b/Tests/RunCMake/cmake_language/defer_call_error-stderr.txt
new file mode 100644
index 0000000..63ce145
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_call_error-stderr.txt
@@ -0,0 +1,9 @@
+^CMake Error at defer_call_error.cmake:2 \(message\):
+ Deferred Error
+Call Stack \(most recent call first\):
+ CMakeLists.txt:DEFERRED
++
+CMake Error at defer_call_error/CMakeLists.txt:2 \(message\):
+ Deferred Error from Subdirectory
+Call Stack \(most recent call first\):
+ CMakeLists.txt:DEFERRED$
diff --git a/Tests/RunCMake/cmake_language/defer_call_error.cmake b/Tests/RunCMake/cmake_language/defer_call_error.cmake
new file mode 100644
index 0000000..083e82a
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_call_error.cmake
@@ -0,0 +1,3 @@
+# Error message backtrace points here but call stack shows DEFERRED execution.
+cmake_language(DEFER CALL message SEND_ERROR "Deferred Error")
+add_subdirectory(defer_call_error)
diff --git a/Tests/RunCMake/cmake_language/defer_call_error/CMakeLists.txt b/Tests/RunCMake/cmake_language/defer_call_error/CMakeLists.txt
new file mode 100644
index 0000000..0acac69
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_call_error/CMakeLists.txt
@@ -0,0 +1,2 @@
+# Error message backtrace points here but call stack shows DEFERRED execution in parent.
+cmake_language(DEFER DIRECTORY .. CALL message SEND_ERROR "Deferred Error from Subdirectory")
diff --git a/Tests/RunCMake/cmake_language/defer_call_ids-stdout.txt b/Tests/RunCMake/cmake_language/defer_call_ids-stdout.txt
new file mode 100644
index 0000000..2fd194d
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_call_ids-stdout.txt
@@ -0,0 +1,13 @@
+-- Immediate Message: ids='message0;getCallIds1;messageIds1;cancelCall;getCallIds2;messageIds2;toBeCancelled;message3'
+-- Immediate Message: message0='message;STATUS;First Deferred Message'
+-- Immediate Message: getCallIds1='cmake_language;DEFER;GET_CALL_IDS;ids'
+-- Immediate Message: messageIds1='cmake_language;EVAL;CODE;message\(STATUS "Deferred Message: ids='\${ids}'"\)'
+-- Immediate Message: cancelCall='cmake_language;DEFER;CANCEL_CALL;toBeCancelled'
+-- Immediate Message: getCallIds2='cmake_language;DEFER;GET_CALL_IDS;ids'
+-- Immediate Message: messageIds2='cmake_language;EVAL;CODE;message\(STATUS "Deferred Message: ids='\${ids}'"\)'
+-- Immediate Message: toBeCancelled='message;STATUS;Cancelled Message'
+-- Immediate Message: message3='message;STATUS;Final Deferred Message'
+-- First Deferred Message
+-- Deferred Message: ids='messageIds1;cancelCall;getCallIds2;messageIds2;toBeCancelled;message3'
+-- Deferred Message: ids='messageIds2;message3'
+-- Final Deferred Message
diff --git a/Tests/RunCMake/cmake_language/defer_call_ids.cmake b/Tests/RunCMake/cmake_language/defer_call_ids.cmake
new file mode 100644
index 0000000..2874894
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_call_ids.cmake
@@ -0,0 +1,14 @@
+cmake_language(DEFER ID message0 CALL message STATUS "First Deferred Message")
+cmake_language(DEFER ID getCallIds1 CALL cmake_language DEFER GET_CALL_IDS ids)
+cmake_language(DEFER ID messageIds1 CALL cmake_language EVAL CODE [[message(STATUS "Deferred Message: ids='${ids}'")]])
+cmake_language(DEFER ID cancelCall CALL cmake_language DEFER CANCEL_CALL toBeCancelled)
+cmake_language(DEFER ID getCallIds2 CALL cmake_language DEFER GET_CALL_IDS ids)
+cmake_language(DEFER ID messageIds2 CALL cmake_language EVAL CODE [[message(STATUS "Deferred Message: ids='${ids}'")]])
+cmake_language(DEFER ID toBeCancelled CALL message STATUS "Cancelled Message")
+cmake_language(DEFER ID message3 CALL message STATUS "Final Deferred Message")
+cmake_language(DEFER GET_CALL_IDS ids)
+message(STATUS "Immediate Message: ids='${ids}'")
+foreach(id ${ids})
+ cmake_language(DEFER GET_CALL ${id} call)
+ message(STATUS "Immediate Message: ${id}='${call}'")
+endforeach()
diff --git a/Tests/RunCMake/cmake_language/defer_call_invalid_command-result.txt b/Tests/RunCMake/cmake_language/defer_call_invalid_command-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_call_invalid_command-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_language/defer_call_invalid_command-stderr.txt b/Tests/RunCMake/cmake_language/defer_call_invalid_command-stderr.txt
new file mode 100644
index 0000000..4cdbf0c
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_call_invalid_command-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at defer_call_invalid_command.cmake:1 \(cmake_language\):
+ cmake_language invalid command specified: [A-Za-z_]+
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/cmake_language/defer_call_invalid_command.cmake b/Tests/RunCMake/cmake_language/defer_call_invalid_command.cmake
new file mode 100644
index 0000000..d6cc936
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_call_invalid_command.cmake
@@ -0,0 +1 @@
+cmake_language(DEFER CALL ${command})
diff --git a/Tests/RunCMake/cmake_language/defer_call_invalid_directory-result.txt b/Tests/RunCMake/cmake_language/defer_call_invalid_directory-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_call_invalid_directory-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_language/defer_call_invalid_directory-stderr.txt b/Tests/RunCMake/cmake_language/defer_call_invalid_directory-stderr.txt
new file mode 100644
index 0000000..afe9a0e
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_call_invalid_directory-stderr.txt
@@ -0,0 +1,9 @@
+^CMake Error at defer_call_invalid_directory.cmake:2 \(cmake_language\):
+ cmake_language DEFER CALL may not be scheduled in directory:
+
+ [^
+]*/Tests/RunCMake/cmake_language/defer_call_invalid_directory-build/defer_call_invalid_directory
+
+ at this time.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/cmake_language/defer_call_invalid_directory.cmake b/Tests/RunCMake/cmake_language/defer_call_invalid_directory.cmake
new file mode 100644
index 0000000..cc1eb8d
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_call_invalid_directory.cmake
@@ -0,0 +1,2 @@
+add_subdirectory(defer_call_invalid_directory)
+cmake_language(DEFER DIRECTORY defer_call_invalid_directory CALL message "Should not be allowed.")
diff --git a/Tests/RunCMake/cmake_language/defer_call_invalid_directory/CMakeLists.txt b/Tests/RunCMake/cmake_language/defer_call_invalid_directory/CMakeLists.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_call_invalid_directory/CMakeLists.txt
diff --git a/Tests/RunCMake/cmake_language/defer_call_missing_directory-result.txt b/Tests/RunCMake/cmake_language/defer_call_missing_directory-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_call_missing_directory-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_language/defer_call_missing_directory-stderr.txt b/Tests/RunCMake/cmake_language/defer_call_missing_directory-stderr.txt
new file mode 100644
index 0000000..db4f90e
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_call_missing_directory-stderr.txt
@@ -0,0 +1,9 @@
+^CMake Error at defer_call_missing_directory.cmake:1 \(cmake_language\):
+ cmake_language DEFER DIRECTORY:
+
+ [^
+]*/Tests/RunCMake/cmake_language/does_not_exist
+
+ is not known. It may not have been processed yet.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/cmake_language/defer_call_missing_directory.cmake b/Tests/RunCMake/cmake_language/defer_call_missing_directory.cmake
new file mode 100644
index 0000000..01f4c40
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_call_missing_directory.cmake
@@ -0,0 +1 @@
+cmake_language(DEFER DIRECTORY does_not_exist CALL message "Should not be allowed.")
diff --git a/Tests/RunCMake/cmake_language/defer_call_policy_PUSH-result.txt b/Tests/RunCMake/cmake_language/defer_call_policy_PUSH-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_call_policy_PUSH-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_language/defer_call_policy_PUSH-stderr.txt b/Tests/RunCMake/cmake_language/defer_call_policy_PUSH-stderr.txt
new file mode 100644
index 0000000..923be13
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_call_policy_PUSH-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error at CMakeLists.txt:DEFERRED:
+ cmake_policy PUSH without matching POP$
diff --git a/Tests/RunCMake/cmake_language/defer_call_policy_PUSH.cmake b/Tests/RunCMake/cmake_language/defer_call_policy_PUSH.cmake
new file mode 100644
index 0000000..66cb760
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_call_policy_PUSH.cmake
@@ -0,0 +1 @@
+cmake_language(DEFER CALL cmake_policy PUSH)
diff --git a/Tests/RunCMake/cmake_language/defer_call_syntax_error-result.txt b/Tests/RunCMake/cmake_language/defer_call_syntax_error-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_call_syntax_error-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_language/defer_call_syntax_error-stderr.txt b/Tests/RunCMake/cmake_language/defer_call_syntax_error-stderr.txt
new file mode 100644
index 0000000..80db4aa
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_call_syntax_error-stderr.txt
@@ -0,0 +1,13 @@
+^CMake Error at defer_call_syntax_error.cmake:2 \(message\):
+ Syntax error in cmake code at
+
+ [^
+]*/Tests/RunCMake/cmake_language/defer_call_syntax_error.cmake:2
+
+ when parsing string
+
+ Deferred \\X Error
+
+ Invalid character escape '\\X'.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:DEFERRED$
diff --git a/Tests/RunCMake/cmake_language/defer_call_syntax_error.cmake b/Tests/RunCMake/cmake_language/defer_call_syntax_error.cmake
new file mode 100644
index 0000000..c3c044b
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_call_syntax_error.cmake
@@ -0,0 +1,2 @@
+# Argument syntax error evaluated at deferred call site.
+cmake_language(DEFER CALL message "Deferred \X Error")
diff --git a/Tests/RunCMake/cmake_language/defer_call_trace-stderr.txt b/Tests/RunCMake/cmake_language/defer_call_trace-stderr.txt
new file mode 100644
index 0000000..b61b236
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_call_trace-stderr.txt
@@ -0,0 +1,8 @@
+[^
+]*/Tests/RunCMake/cmake_language/defer_call_trace.cmake\(2\): cmake_language\(DEFER CALL message Deferred Message \)
+[^
+]*/Tests/RunCMake/cmake_language/defer_call_trace.cmake\(3\): message\(Immediate Message \)
+Immediate Message
+[^
+]*/Tests/RunCMake/cmake_language/defer_call_trace.cmake\(2\):DEFERRED:__0: message\(Deferred Message \)
+Deferred Message$
diff --git a/Tests/RunCMake/cmake_language/defer_call_trace.cmake b/Tests/RunCMake/cmake_language/defer_call_trace.cmake
new file mode 100644
index 0000000..5ed383f
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_call_trace.cmake
@@ -0,0 +1,3 @@
+# The --trace and --trace-expand output point here for deferred call.
+cmake_language(DEFER CALL message "Deferred Message")
+message("Immediate Message")
diff --git a/Tests/RunCMake/cmake_language/defer_call_trace_json-stderr.txt b/Tests/RunCMake/cmake_language/defer_call_trace_json-stderr.txt
new file mode 100644
index 0000000..647beb0
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_call_trace_json-stderr.txt
@@ -0,0 +1,5 @@
+{"args":\["DEFER","CALL","message","Deferred Message"\],"cmd":"cmake_language","file":"[^"]*/Tests/RunCMake/cmake_language/defer_call_trace_json.cmake","frame":2,"line":2,"time":[0-9.]+}
+{"args":\["Immediate Message"\],"cmd":"message","file":"[^"]*/Tests/RunCMake/cmake_language/defer_call_trace_json.cmake","frame":2,"line":3,"time":[0-9.]+}
+Immediate Message
+{"args":\["Deferred Message"],"cmd":"message","defer":"__0","file":"[^"]*/Tests/RunCMake/cmake_language/defer_call_trace_json.cmake","frame":1,"line":2,"time":[0-9.]+}
+Deferred Message$
diff --git a/Tests/RunCMake/cmake_language/defer_call_trace_json.cmake b/Tests/RunCMake/cmake_language/defer_call_trace_json.cmake
new file mode 100644
index 0000000..5ed383f
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_call_trace_json.cmake
@@ -0,0 +1,3 @@
+# The --trace and --trace-expand output point here for deferred call.
+cmake_language(DEFER CALL message "Deferred Message")
+message("Immediate Message")
diff --git a/Tests/RunCMake/cmake_language/defer_cancel_call_id-result.txt b/Tests/RunCMake/cmake_language/defer_cancel_call_id-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_cancel_call_id-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_language/defer_cancel_call_id-stderr.txt b/Tests/RunCMake/cmake_language/defer_cancel_call_id-stderr.txt
new file mode 100644
index 0000000..8a13c0d
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_cancel_call_id-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at defer_cancel_call_id.cmake:1 \(cmake_language\):
+ cmake_language DEFER CANCEL_CALL does not accept ID or ID_VAR.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/cmake_language/defer_cancel_call_id.cmake b/Tests/RunCMake/cmake_language/defer_cancel_call_id.cmake
new file mode 100644
index 0000000..6e5b5c8
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_cancel_call_id.cmake
@@ -0,0 +1 @@
+cmake_language(DEFER ID id CANCEL_CALL)
diff --git a/Tests/RunCMake/cmake_language/defer_cancel_call_id_var-result.txt b/Tests/RunCMake/cmake_language/defer_cancel_call_id_var-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_cancel_call_id_var-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_language/defer_cancel_call_id_var-stderr.txt b/Tests/RunCMake/cmake_language/defer_cancel_call_id_var-stderr.txt
new file mode 100644
index 0000000..5783c50
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_cancel_call_id_var-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at defer_cancel_call_id_var.cmake:1 \(cmake_language\):
+ cmake_language DEFER CANCEL_CALL does not accept ID or ID_VAR.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/cmake_language/defer_cancel_call_id_var.cmake b/Tests/RunCMake/cmake_language/defer_cancel_call_id_var.cmake
new file mode 100644
index 0000000..9f75221
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_cancel_call_id_var.cmake
@@ -0,0 +1 @@
+cmake_language(DEFER ID_VAR id_var CANCEL_CALL)
diff --git a/Tests/RunCMake/cmake_language/defer_cancel_call_invalid_directory-result.txt b/Tests/RunCMake/cmake_language/defer_cancel_call_invalid_directory-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_cancel_call_invalid_directory-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_language/defer_cancel_call_invalid_directory-stderr.txt b/Tests/RunCMake/cmake_language/defer_cancel_call_invalid_directory-stderr.txt
new file mode 100644
index 0000000..cacbf9a
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_cancel_call_invalid_directory-stderr.txt
@@ -0,0 +1,9 @@
+^CMake Error at defer_cancel_call_invalid_directory.cmake:2 \(cmake_language\):
+ cmake_language DEFER CANCEL_CALL may not update directory:
+
+ [^
+]*/Tests/RunCMake/cmake_language/defer_cancel_call_invalid_directory-build/defer_cancel_call_invalid_directory
+
+ at this time.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/cmake_language/defer_cancel_call_invalid_directory.cmake b/Tests/RunCMake/cmake_language/defer_cancel_call_invalid_directory.cmake
new file mode 100644
index 0000000..29a8fc2
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_cancel_call_invalid_directory.cmake
@@ -0,0 +1,2 @@
+add_subdirectory(defer_cancel_call_invalid_directory)
+cmake_language(DEFER DIRECTORY defer_cancel_call_invalid_directory CANCEL_CALL _)
diff --git a/Tests/RunCMake/cmake_language/defer_cancel_call_invalid_directory/CMakeLists.txt b/Tests/RunCMake/cmake_language/defer_cancel_call_invalid_directory/CMakeLists.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_cancel_call_invalid_directory/CMakeLists.txt
diff --git a/Tests/RunCMake/cmake_language/defer_cancel_call_unknown_argument-result.txt b/Tests/RunCMake/cmake_language/defer_cancel_call_unknown_argument-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_cancel_call_unknown_argument-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_language/defer_cancel_call_unknown_argument-stderr.txt b/Tests/RunCMake/cmake_language/defer_cancel_call_unknown_argument-stderr.txt
new file mode 100644
index 0000000..eb8f2b9
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_cancel_call_unknown_argument-stderr.txt
@@ -0,0 +1,6 @@
+^CMake Error at defer_cancel_call_unknown_argument.cmake:1 \(cmake_language\):
+ cmake_language DEFER CANCEL_CALL unknown argument:
+
+ UNKNOWN
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/cmake_language/defer_cancel_call_unknown_argument.cmake b/Tests/RunCMake/cmake_language/defer_cancel_call_unknown_argument.cmake
new file mode 100644
index 0000000..fbc6309
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_cancel_call_unknown_argument.cmake
@@ -0,0 +1 @@
+cmake_language(DEFER CANCEL_CALL UNKNOWN)
diff --git a/Tests/RunCMake/cmake_language/defer_directory_empty-result.txt b/Tests/RunCMake/cmake_language/defer_directory_empty-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_directory_empty-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_language/defer_directory_empty-stderr.txt b/Tests/RunCMake/cmake_language/defer_directory_empty-stderr.txt
new file mode 100644
index 0000000..587dfa9
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_directory_empty-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at defer_directory_empty.cmake:1 \(cmake_language\):
+ cmake_language DEFER DIRECTORY may not be empty
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/cmake_language/defer_directory_empty.cmake b/Tests/RunCMake/cmake_language/defer_directory_empty.cmake
new file mode 100644
index 0000000..f4e4553
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_directory_empty.cmake
@@ -0,0 +1 @@
+cmake_language(DEFER DIRECTORY "")
diff --git a/Tests/RunCMake/cmake_language/defer_directory_missing-result.txt b/Tests/RunCMake/cmake_language/defer_directory_missing-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_directory_missing-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_language/defer_directory_missing-stderr.txt b/Tests/RunCMake/cmake_language/defer_directory_missing-stderr.txt
new file mode 100644
index 0000000..1db8e99
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_directory_missing-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at defer_directory_missing.cmake:1 \(cmake_language\):
+ cmake_language DEFER DIRECTORY missing value
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/cmake_language/defer_directory_missing.cmake b/Tests/RunCMake/cmake_language/defer_directory_missing.cmake
new file mode 100644
index 0000000..fbdb177
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_directory_missing.cmake
@@ -0,0 +1 @@
+cmake_language(DEFER DIRECTORY)
diff --git a/Tests/RunCMake/cmake_language/defer_directory_multiple-result.txt b/Tests/RunCMake/cmake_language/defer_directory_multiple-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_directory_multiple-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_language/defer_directory_multiple-stderr.txt b/Tests/RunCMake/cmake_language/defer_directory_multiple-stderr.txt
new file mode 100644
index 0000000..f4d09b9
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_directory_multiple-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at defer_directory_multiple.cmake:1 \(cmake_language\):
+ cmake_language DEFER given multiple DIRECTORY arguments
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/cmake_language/defer_directory_multiple.cmake b/Tests/RunCMake/cmake_language/defer_directory_multiple.cmake
new file mode 100644
index 0000000..baf037b
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_directory_multiple.cmake
@@ -0,0 +1 @@
+cmake_language(DEFER DIRECTORY . DIRECTORY x CALL message "Should not be allowed.")
diff --git a/Tests/RunCMake/cmake_language/defer_get_call_id-result.txt b/Tests/RunCMake/cmake_language/defer_get_call_id-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_get_call_id-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_language/defer_get_call_id-stderr.txt b/Tests/RunCMake/cmake_language/defer_get_call_id-stderr.txt
new file mode 100644
index 0000000..e161a5f
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_get_call_id-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at defer_get_call_id.cmake:1 \(cmake_language\):
+ cmake_language DEFER GET_CALL does not accept ID or ID_VAR.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/cmake_language/defer_get_call_id.cmake b/Tests/RunCMake/cmake_language/defer_get_call_id.cmake
new file mode 100644
index 0000000..7a395ea
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_get_call_id.cmake
@@ -0,0 +1 @@
+cmake_language(DEFER ID id GET_CALL)
diff --git a/Tests/RunCMake/cmake_language/defer_get_call_id_empty-result.txt b/Tests/RunCMake/cmake_language/defer_get_call_id_empty-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_get_call_id_empty-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_language/defer_get_call_id_empty-stderr.txt b/Tests/RunCMake/cmake_language/defer_get_call_id_empty-stderr.txt
new file mode 100644
index 0000000..c7c534b
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_get_call_id_empty-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at defer_get_call_id_empty.cmake:1 \(cmake_language\):
+ cmake_language DEFER GET_CALL id may not be empty
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/cmake_language/defer_get_call_id_empty.cmake b/Tests/RunCMake/cmake_language/defer_get_call_id_empty.cmake
new file mode 100644
index 0000000..4f39f2d
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_get_call_id_empty.cmake
@@ -0,0 +1 @@
+cmake_language(DEFER GET_CALL "" var)
diff --git a/Tests/RunCMake/cmake_language/defer_get_call_id_var-result.txt b/Tests/RunCMake/cmake_language/defer_get_call_id_var-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_get_call_id_var-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_language/defer_get_call_id_var-stderr.txt b/Tests/RunCMake/cmake_language/defer_get_call_id_var-stderr.txt
new file mode 100644
index 0000000..2cfd942
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_get_call_id_var-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at defer_get_call_id_var.cmake:1 \(cmake_language\):
+ cmake_language DEFER GET_CALL does not accept ID or ID_VAR.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/cmake_language/defer_get_call_id_var.cmake b/Tests/RunCMake/cmake_language/defer_get_call_id_var.cmake
new file mode 100644
index 0000000..ade0815
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_get_call_id_var.cmake
@@ -0,0 +1 @@
+cmake_language(DEFER ID_VAR id_var GET_CALL)
diff --git a/Tests/RunCMake/cmake_language/defer_get_call_ids_id-result.txt b/Tests/RunCMake/cmake_language/defer_get_call_ids_id-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_get_call_ids_id-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_language/defer_get_call_ids_id-stderr.txt b/Tests/RunCMake/cmake_language/defer_get_call_ids_id-stderr.txt
new file mode 100644
index 0000000..072ee45
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_get_call_ids_id-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at defer_get_call_ids_id.cmake:1 \(cmake_language\):
+ cmake_language DEFER GET_CALL_IDS does not accept ID or ID_VAR.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/cmake_language/defer_get_call_ids_id.cmake b/Tests/RunCMake/cmake_language/defer_get_call_ids_id.cmake
new file mode 100644
index 0000000..4eb2555
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_get_call_ids_id.cmake
@@ -0,0 +1 @@
+cmake_language(DEFER ID id GET_CALL_IDS)
diff --git a/Tests/RunCMake/cmake_language/defer_get_call_ids_id_var-result.txt b/Tests/RunCMake/cmake_language/defer_get_call_ids_id_var-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_get_call_ids_id_var-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_language/defer_get_call_ids_id_var-stderr.txt b/Tests/RunCMake/cmake_language/defer_get_call_ids_id_var-stderr.txt
new file mode 100644
index 0000000..e4a288c
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_get_call_ids_id_var-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at defer_get_call_ids_id_var.cmake:1 \(cmake_language\):
+ cmake_language DEFER GET_CALL_IDS does not accept ID or ID_VAR.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/cmake_language/defer_get_call_ids_id_var.cmake b/Tests/RunCMake/cmake_language/defer_get_call_ids_id_var.cmake
new file mode 100644
index 0000000..c27de79
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_get_call_ids_id_var.cmake
@@ -0,0 +1 @@
+cmake_language(DEFER ID_VAR id_var GET_CALL_IDS)
diff --git a/Tests/RunCMake/cmake_language/defer_get_call_ids_invalid_directory-result.txt b/Tests/RunCMake/cmake_language/defer_get_call_ids_invalid_directory-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_get_call_ids_invalid_directory-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_language/defer_get_call_ids_invalid_directory-stderr.txt b/Tests/RunCMake/cmake_language/defer_get_call_ids_invalid_directory-stderr.txt
new file mode 100644
index 0000000..edebe32
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_get_call_ids_invalid_directory-stderr.txt
@@ -0,0 +1,9 @@
+^CMake Error at defer_get_call_ids_invalid_directory.cmake:2 \(cmake_language\):
+ cmake_language DEFER GET_CALL_IDS may not access directory:
+
+ [^
+]*/Tests/RunCMake/cmake_language/defer_get_call_ids_invalid_directory-build/defer_get_call_ids_invalid_directory
+
+ at this time.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/cmake_language/defer_get_call_ids_invalid_directory.cmake b/Tests/RunCMake/cmake_language/defer_get_call_ids_invalid_directory.cmake
new file mode 100644
index 0000000..81f098e
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_get_call_ids_invalid_directory.cmake
@@ -0,0 +1,2 @@
+add_subdirectory(defer_get_call_ids_invalid_directory)
+cmake_language(DEFER DIRECTORY defer_get_call_ids_invalid_directory GET_CALL_IDS var)
diff --git a/Tests/RunCMake/cmake_language/defer_get_call_ids_invalid_directory/CMakeLists.txt b/Tests/RunCMake/cmake_language/defer_get_call_ids_invalid_directory/CMakeLists.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_get_call_ids_invalid_directory/CMakeLists.txt
diff --git a/Tests/RunCMake/cmake_language/defer_get_call_ids_missing_var-result.txt b/Tests/RunCMake/cmake_language/defer_get_call_ids_missing_var-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_get_call_ids_missing_var-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_language/defer_get_call_ids_missing_var-stderr.txt b/Tests/RunCMake/cmake_language/defer_get_call_ids_missing_var-stderr.txt
new file mode 100644
index 0000000..a2951cf
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_get_call_ids_missing_var-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at defer_get_call_ids_missing_var.cmake:1 \(cmake_language\):
+ cmake_language DEFER GET_CALL_IDS missing output variable
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/cmake_language/defer_get_call_ids_missing_var.cmake b/Tests/RunCMake/cmake_language/defer_get_call_ids_missing_var.cmake
new file mode 100644
index 0000000..b171f04
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_get_call_ids_missing_var.cmake
@@ -0,0 +1 @@
+cmake_language(DEFER GET_CALL_IDS)
diff --git a/Tests/RunCMake/cmake_language/defer_get_call_ids_too_many_args-result.txt b/Tests/RunCMake/cmake_language/defer_get_call_ids_too_many_args-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_get_call_ids_too_many_args-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_language/defer_get_call_ids_too_many_args-stderr.txt b/Tests/RunCMake/cmake_language/defer_get_call_ids_too_many_args-stderr.txt
new file mode 100644
index 0000000..5691519
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_get_call_ids_too_many_args-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at defer_get_call_ids_too_many_args.cmake:1 \(cmake_language\):
+ cmake_language DEFER GET_CALL_IDS given too many arguments
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/cmake_language/defer_get_call_ids_too_many_args.cmake b/Tests/RunCMake/cmake_language/defer_get_call_ids_too_many_args.cmake
new file mode 100644
index 0000000..0158684
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_get_call_ids_too_many_args.cmake
@@ -0,0 +1 @@
+cmake_language(DEFER GET_CALL_IDS var extra)
diff --git a/Tests/RunCMake/cmake_language/defer_get_call_missing_id-result.txt b/Tests/RunCMake/cmake_language/defer_get_call_missing_id-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_get_call_missing_id-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_language/defer_get_call_missing_id-stderr.txt b/Tests/RunCMake/cmake_language/defer_get_call_missing_id-stderr.txt
new file mode 100644
index 0000000..081aa95
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_get_call_missing_id-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at defer_get_call_missing_id.cmake:1 \(cmake_language\):
+ cmake_language DEFER GET_CALL missing id
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/cmake_language/defer_get_call_missing_id.cmake b/Tests/RunCMake/cmake_language/defer_get_call_missing_id.cmake
new file mode 100644
index 0000000..0542abc
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_get_call_missing_id.cmake
@@ -0,0 +1 @@
+cmake_language(DEFER GET_CALL)
diff --git a/Tests/RunCMake/cmake_language/defer_get_call_missing_var-result.txt b/Tests/RunCMake/cmake_language/defer_get_call_missing_var-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_get_call_missing_var-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_language/defer_get_call_missing_var-stderr.txt b/Tests/RunCMake/cmake_language/defer_get_call_missing_var-stderr.txt
new file mode 100644
index 0000000..1b2641f
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_get_call_missing_var-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at defer_get_call_missing_var.cmake:1 \(cmake_language\):
+ cmake_language DEFER GET_CALL missing output variable
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/cmake_language/defer_get_call_missing_var.cmake b/Tests/RunCMake/cmake_language/defer_get_call_missing_var.cmake
new file mode 100644
index 0000000..7916d29
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_get_call_missing_var.cmake
@@ -0,0 +1 @@
+cmake_language(DEFER GET_CALL id)
diff --git a/Tests/RunCMake/cmake_language/defer_get_call_too_many_args-result.txt b/Tests/RunCMake/cmake_language/defer_get_call_too_many_args-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_get_call_too_many_args-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_language/defer_get_call_too_many_args-stderr.txt b/Tests/RunCMake/cmake_language/defer_get_call_too_many_args-stderr.txt
new file mode 100644
index 0000000..b6ee2d6
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_get_call_too_many_args-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at defer_get_call_too_many_args.cmake:1 \(cmake_language\):
+ cmake_language DEFER GET_CALL given too many arguments
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/cmake_language/defer_get_call_too_many_args.cmake b/Tests/RunCMake/cmake_language/defer_get_call_too_many_args.cmake
new file mode 100644
index 0000000..ed65779
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_get_call_too_many_args.cmake
@@ -0,0 +1 @@
+cmake_language(DEFER GET_CALL id var extra)
diff --git a/Tests/RunCMake/cmake_language/defer_get_call_unknown_argument-result.txt b/Tests/RunCMake/cmake_language/defer_get_call_unknown_argument-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_get_call_unknown_argument-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_language/defer_get_call_unknown_argument-stderr.txt b/Tests/RunCMake/cmake_language/defer_get_call_unknown_argument-stderr.txt
new file mode 100644
index 0000000..ac16596
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_get_call_unknown_argument-stderr.txt
@@ -0,0 +1,6 @@
+^CMake Error at defer_get_call_unknown_argument.cmake:1 \(cmake_language\):
+ cmake_language DEFER GET_CALL unknown argument:
+
+ UNKNOWN
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/cmake_language/defer_get_call_unknown_argument.cmake b/Tests/RunCMake/cmake_language/defer_get_call_unknown_argument.cmake
new file mode 100644
index 0000000..d0caa39
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_get_call_unknown_argument.cmake
@@ -0,0 +1 @@
+cmake_language(DEFER GET_CALL UNKNOWN var)
diff --git a/Tests/RunCMake/cmake_language/defer_id_empty-result.txt b/Tests/RunCMake/cmake_language/defer_id_empty-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_id_empty-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_language/defer_id_empty-stderr.txt b/Tests/RunCMake/cmake_language/defer_id_empty-stderr.txt
new file mode 100644
index 0000000..1e7f772
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_id_empty-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at defer_id_empty.cmake:1 \(cmake_language\):
+ cmake_language DEFER ID may not be empty
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/cmake_language/defer_id_empty.cmake b/Tests/RunCMake/cmake_language/defer_id_empty.cmake
new file mode 100644
index 0000000..326762c
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_id_empty.cmake
@@ -0,0 +1 @@
+cmake_language(DEFER ID "")
diff --git a/Tests/RunCMake/cmake_language/defer_id_missing-result.txt b/Tests/RunCMake/cmake_language/defer_id_missing-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_id_missing-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_language/defer_id_missing-stderr.txt b/Tests/RunCMake/cmake_language/defer_id_missing-stderr.txt
new file mode 100644
index 0000000..cef5f0e
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_id_missing-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at defer_id_missing.cmake:1 \(cmake_language\):
+ cmake_language DEFER ID missing value
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/cmake_language/defer_id_missing.cmake b/Tests/RunCMake/cmake_language/defer_id_missing.cmake
new file mode 100644
index 0000000..4de687d
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_id_missing.cmake
@@ -0,0 +1 @@
+cmake_language(DEFER ID)
diff --git a/Tests/RunCMake/cmake_language/defer_id_multiple-result.txt b/Tests/RunCMake/cmake_language/defer_id_multiple-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_id_multiple-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_language/defer_id_multiple-stderr.txt b/Tests/RunCMake/cmake_language/defer_id_multiple-stderr.txt
new file mode 100644
index 0000000..1725521
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_id_multiple-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at defer_id_multiple.cmake:1 \(cmake_language\):
+ cmake_language DEFER given multiple ID arguments
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/cmake_language/defer_id_multiple.cmake b/Tests/RunCMake/cmake_language/defer_id_multiple.cmake
new file mode 100644
index 0000000..69187af
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_id_multiple.cmake
@@ -0,0 +1 @@
+cmake_language(DEFER ID a ID b CALL message "Should not be allowed.")
diff --git a/Tests/RunCMake/cmake_language/defer_id_var_empty-result.txt b/Tests/RunCMake/cmake_language/defer_id_var_empty-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_id_var_empty-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_language/defer_id_var_empty-stderr.txt b/Tests/RunCMake/cmake_language/defer_id_var_empty-stderr.txt
new file mode 100644
index 0000000..bb5cd43
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_id_var_empty-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at defer_id_var_empty.cmake:1 \(cmake_language\):
+ cmake_language DEFER ID_VAR may not be empty
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/cmake_language/defer_id_var_empty.cmake b/Tests/RunCMake/cmake_language/defer_id_var_empty.cmake
new file mode 100644
index 0000000..c7198f5
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_id_var_empty.cmake
@@ -0,0 +1 @@
+cmake_language(DEFER ID_VAR "")
diff --git a/Tests/RunCMake/cmake_language/defer_id_var_missing-result.txt b/Tests/RunCMake/cmake_language/defer_id_var_missing-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_id_var_missing-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_language/defer_id_var_missing-stderr.txt b/Tests/RunCMake/cmake_language/defer_id_var_missing-stderr.txt
new file mode 100644
index 0000000..f4e0d6e
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_id_var_missing-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at defer_id_var_missing.cmake:1 \(cmake_language\):
+ cmake_language DEFER ID_VAR missing variable name
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/cmake_language/defer_id_var_missing.cmake b/Tests/RunCMake/cmake_language/defer_id_var_missing.cmake
new file mode 100644
index 0000000..359d149
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_id_var_missing.cmake
@@ -0,0 +1 @@
+cmake_language(DEFER ID_VAR)
diff --git a/Tests/RunCMake/cmake_language/defer_id_var_multiple-result.txt b/Tests/RunCMake/cmake_language/defer_id_var_multiple-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_id_var_multiple-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_language/defer_id_var_multiple-stderr.txt b/Tests/RunCMake/cmake_language/defer_id_var_multiple-stderr.txt
new file mode 100644
index 0000000..4368b06
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_id_var_multiple-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at defer_id_var_multiple.cmake:1 \(cmake_language\):
+ cmake_language DEFER given multiple ID_VAR arguments
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/cmake_language/defer_id_var_multiple.cmake b/Tests/RunCMake/cmake_language/defer_id_var_multiple.cmake
new file mode 100644
index 0000000..665ea94
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_id_var_multiple.cmake
@@ -0,0 +1 @@
+cmake_language(DEFER ID_VAR a ID_VAR b CALL message "Should not be allowed.")
diff --git a/Tests/RunCMake/cmake_language/defer_missing_arg-result.txt b/Tests/RunCMake/cmake_language/defer_missing_arg-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_missing_arg-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_language/defer_missing_arg-stderr.txt b/Tests/RunCMake/cmake_language/defer_missing_arg-stderr.txt
new file mode 100644
index 0000000..3e656cd
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_missing_arg-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at defer_missing_arg.cmake:1 \(cmake_language\):
+ cmake_language DEFER requires at least one argument
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/cmake_language/defer_missing_arg.cmake b/Tests/RunCMake/cmake_language/defer_missing_arg.cmake
new file mode 100644
index 0000000..737a8c8
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_missing_arg.cmake
@@ -0,0 +1 @@
+cmake_language(DEFER)
diff --git a/Tests/RunCMake/cmake_language/defer_missing_call-result.txt b/Tests/RunCMake/cmake_language/defer_missing_call-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_missing_call-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_language/defer_missing_call-stderr.txt b/Tests/RunCMake/cmake_language/defer_missing_call-stderr.txt
new file mode 100644
index 0000000..7eeef76
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_missing_call-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at defer_missing_call.cmake:1 \(cmake_language\):
+ cmake_language DEFER must be followed by a CALL argument
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/cmake_language/defer_missing_call.cmake b/Tests/RunCMake/cmake_language/defer_missing_call.cmake
new file mode 100644
index 0000000..0b330ef
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_missing_call.cmake
@@ -0,0 +1 @@
+cmake_language(DEFER DIRECTORY .)
diff --git a/Tests/RunCMake/cmake_language/defer_unknown_option-result.txt b/Tests/RunCMake/cmake_language/defer_unknown_option-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_unknown_option-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_language/defer_unknown_option-stderr.txt b/Tests/RunCMake/cmake_language/defer_unknown_option-stderr.txt
new file mode 100644
index 0000000..95d87c6
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_unknown_option-stderr.txt
@@ -0,0 +1,6 @@
+^CMake Error at defer_unknown_option.cmake:1 \(cmake_language\):
+ cmake_language DEFER unknown option:
+
+ UNKNOWN
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/cmake_language/defer_unknown_option.cmake b/Tests/RunCMake/cmake_language/defer_unknown_option.cmake
new file mode 100644
index 0000000..876b3f1
--- /dev/null
+++ b/Tests/RunCMake/cmake_language/defer_unknown_option.cmake
@@ -0,0 +1 @@
+cmake_language(DEFER UNKNOWN)
diff --git a/Tests/RunCMake/cmake_language/no_parameters-stderr.txt b/Tests/RunCMake/cmake_language/no_parameters-stderr.txt
index 194bbe3..1862c77 100644
--- a/Tests/RunCMake/cmake_language/no_parameters-stderr.txt
+++ b/Tests/RunCMake/cmake_language/no_parameters-stderr.txt
@@ -1,2 +1,2 @@
CMake Error at no_parameters.cmake:1 \(cmake_language\):
- cmake_language called with incorrect number of arguments
+ cmake_language CALL missing command name
diff --git a/Tests/RunCMake/ctest_build/BuildCommandFailure-check.cmake b/Tests/RunCMake/ctest_build/BuildCommandFailure-check.cmake
new file mode 100644
index 0000000..feac3ce
--- /dev/null
+++ b/Tests/RunCMake/ctest_build/BuildCommandFailure-check.cmake
@@ -0,0 +1,12 @@
+file(GLOB build_xml_file "${RunCMake_TEST_BINARY_DIR}/Testing/*/Build.xml")
+if(build_xml_file)
+ file(READ "${build_xml_file}" build_xml LIMIT 4096)
+ if(NOT build_xml MATCHES [[this command failed]])
+ string(REPLACE "\n" "\n " build_xml " ${build_xml}")
+ set(RunCMake_TEST_FAILED
+ "Build.xml does not have expected error message:\n${build_xml}"
+ )
+ endif()
+else()
+ set(RunCMake_TEST_FAILED "Build.xml not found")
+endif()
diff --git a/Tests/RunCMake/ctest_build/BuildCommandFailure-result.txt b/Tests/RunCMake/ctest_build/BuildCommandFailure-result.txt
new file mode 100644
index 0000000..b57e2de
--- /dev/null
+++ b/Tests/RunCMake/ctest_build/BuildCommandFailure-result.txt
@@ -0,0 +1 @@
+(-1|255)
diff --git a/Tests/RunCMake/ctest_build/BuildCommandFailure-stderr.txt b/Tests/RunCMake/ctest_build/BuildCommandFailure-stderr.txt
new file mode 100644
index 0000000..bbe9410
--- /dev/null
+++ b/Tests/RunCMake/ctest_build/BuildCommandFailure-stderr.txt
@@ -0,0 +1 @@
+^Error\(s\) when building project
diff --git a/Tests/RunCMake/ctest_build/RunCMakeTest.cmake b/Tests/RunCMake/ctest_build/RunCMakeTest.cmake
index b2e562a..072fbac 100644
--- a/Tests/RunCMake/ctest_build/RunCMakeTest.cmake
+++ b/Tests/RunCMake/ctest_build/RunCMakeTest.cmake
@@ -48,8 +48,12 @@ function(run_BuildChangeId)
endfunction()
run_BuildChangeId()
-set(RunCMake_USE_LAUNCHERS FALSE)
set(RunCMake_USE_CUSTOM_BUILD_COMMAND TRUE)
+set(RunCMake_BUILD_COMMAND "${FAKE_BUILD_COMMAND_EXE}")
+run_ctest(BuildCommandFailure)
+unset(RunCMake_BUILD_COMMAND)
+
+set(RunCMake_USE_LAUNCHERS FALSE)
set(RunCMake_BUILD_COMMAND "${COLOR_WARNING}")
run_ctest(IgnoreColor)
unset(RunCMake_BUILD_COMMAND)
diff --git a/Tests/RunCMake/fake_build_command.c b/Tests/RunCMake/fake_build_command.c
new file mode 100644
index 0000000..d87335b
--- /dev/null
+++ b/Tests/RunCMake/fake_build_command.c
@@ -0,0 +1,6 @@
+#include <stdio.h>
+int main(void)
+{
+ printf("this command failed\n");
+ return 1;
+}
diff --git a/Tests/RunCMake/find_package/EmptyVersionRange-result.txt b/Tests/RunCMake/find_package/EmptyVersionRange-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/find_package/EmptyVersionRange-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/find_package/EmptyVersionRange-stderr.txt b/Tests/RunCMake/find_package/EmptyVersionRange-stderr.txt
new file mode 100644
index 0000000..9c00b96
--- /dev/null
+++ b/Tests/RunCMake/find_package/EmptyVersionRange-stderr.txt
@@ -0,0 +1,10 @@
+CMake Error at EmptyVersionRange.cmake:[0-9]+ \(find_package\):
+ find_package specified version range is empty.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)
+
+
+CMake Error at EmptyVersionRange.cmake:[0-9]+ \(find_package\):
+ find_package specified version range is empty.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/find_package/EmptyVersionRange.cmake b/Tests/RunCMake/find_package/EmptyVersionRange.cmake
new file mode 100644
index 0000000..553e297
--- /dev/null
+++ b/Tests/RunCMake/find_package/EmptyVersionRange.cmake
@@ -0,0 +1,3 @@
+find_package(VersionRange 2.3...1.2)
+
+find_package(VersionRange 2.3...<2.3)
diff --git a/Tests/RunCMake/find_package/FindVersionRange.cmake b/Tests/RunCMake/find_package/FindVersionRange.cmake
index ff84e93..27e5b90 100644
--- a/Tests/RunCMake/find_package/FindVersionRange.cmake
+++ b/Tests/RunCMake/find_package/FindVersionRange.cmake
@@ -3,19 +3,19 @@ if (NOT VersionRange_FIND_VERSION_COMPLETE STREQUAL VersionRange_SPECIFIED_VERSI
message (SEND_ERROR "Wrong value for VersionRange_FIND_VERSION_COMPLETE: ${VersionRange_FIND_VERSION_COMPLETE}")
endif()
-if (NOT VersionRange_FIND_VERSION VERSION_EQUAL "1.2.3.4")
+if (NOT VersionRange_FIND_VERSION VERSION_EQUAL VersionRange_SPECIFIED_VERSION_MIN)
message (SEND_ERROR "Wrong value for VersionRange_FIND_VERSION: ${VersionRange_FIND_VERSION}")
endif()
-if (NOT VersionRange_FIND_VERSION_MAJOR VERSION_EQUAL "1")
+if (NOT VersionRange_FIND_VERSION_MAJOR VERSION_EQUAL VersionRange_SPECIFIED_VERSION_MIN_MAJOR)
message (SEND_ERROR "Wrong value for VersionRange_FIND_VERSION_MAJOR: ${VersionRange_FIND_VERSION_MAJOR}")
endif()
-if (NOT VersionRange_FIND_VERSION_MINOR VERSION_EQUAL "2")
+if (NOT VersionRange_FIND_VERSION_MINOR VERSION_EQUAL VersionRange_SPECIFIED_VERSION_MIN_MINOR)
message (SEND_ERROR "Wrong value for VersionRange_FIND_VERSION_MINOR: ${VersionRange_FIND_VERSION_MINOR}")
endif()
-if (NOT VersionRange_FIND_VERSION_PATCH VERSION_EQUAL "3")
+if (NOT VersionRange_FIND_VERSION_PATCH VERSION_EQUAL VersionRange_SPECIFIED_VERSION_MIN_PATCH)
message (SEND_ERROR "Wrong value for VersionRange_FIND_VERSION_PATCH: ${VersionRange_FIND_VERSION_PATCH}")
endif()
-if (NOT VersionRange_FIND_VERSION_TWEAK VERSION_EQUAL "4")
+if (NOT VersionRange_FIND_VERSION_TWEAK VERSION_EQUAL VersionRange_SPECIFIED_VERSION_MIN_TWEAK)
message (SEND_ERROR "Wrong value for VersionRange_FIND_VERSION_TWEAK: ${VersionRange_FIND_VERSION_TWEAK}")
endif()
@@ -35,19 +35,19 @@ else()
endif()
endif()
-if (NOT VersionRange_FIND_VERSION_MIN VERSION_EQUAL "1.2.3.4")
- message (SEND_ERROR "Wrong value for VersionRange_FIND_VERSION_MIN: ${VersionRange_FIND_VERSION}")
+if (NOT VersionRange_FIND_VERSION_MIN VERSION_EQUAL VersionRange_SPECIFIED_VERSION_MIN)
+ message (SEND_ERROR "Wrong value for VersionRange_FIND_VERSION_MIN: ${VersionRange_FIND_VERSION_MIN}")
endif()
-if (NOT VersionRange_FIND_VERSION_MIN_MAJOR VERSION_EQUAL "1")
+if (NOT VersionRange_FIND_VERSION_MIN_MAJOR VERSION_EQUAL VersionRange_SPECIFIED_VERSION_MIN_MAJOR)
message (SEND_ERROR "Wrong value for VersionRange_FIND_VERSION_MIN_MAJOR: ${VersionRange_FIND_VERSION_MIN_MAJOR}")
endif()
-if (NOT VersionRange_FIND_VERSION_MIN_MINOR VERSION_EQUAL "2")
+if (NOT VersionRange_FIND_VERSION_MIN_MINOR VERSION_EQUAL VersionRange_SPECIFIED_VERSION_MIN_MINOR)
message (SEND_ERROR "Wrong value for VersionRange_FIND_VERSION_MIN_MINOR: ${VersionRange_FIND_VERSION_MIN_MINOR}")
endif()
-if (NOT VersionRange_FIND_VERSION_MIN_PATCH VERSION_EQUAL "3")
+if (NOT VersionRange_FIND_VERSION_MIN_PATCH VERSION_EQUAL VersionRange_SPECIFIED_VERSION_MIN_PATCH)
message (SEND_ERROR "Wrong value for VersionRange_FIND_VERSION_MIN_PATCH: ${VersionRange_FIND_VERSION_MIN_PATCH}")
endif()
-if (NOT VersionRange_FIND_VERSION_MIN_TWEAK VERSION_EQUAL "4")
+if (NOT VersionRange_FIND_VERSION_MIN_TWEAK VERSION_EQUAL VersionRange_SPECIFIED_VERSION_MIN_TWEAK)
message (SEND_ERROR "Wrong value for VersionRange_FIND_VERSION_MIN_TWEAK: ${VersionRange_FIND_VERSION_MIN_TWEAK}")
endif()
diff --git a/Tests/RunCMake/find_package/RunCMakeTest.cmake b/Tests/RunCMake/find_package/RunCMakeTest.cmake
index 7755a70..a899f46 100644
--- a/Tests/RunCMake/find_package/RunCMakeTest.cmake
+++ b/Tests/RunCMake/find_package/RunCMakeTest.cmake
@@ -30,10 +30,12 @@ run_cmake(CMP0084-OLD)
run_cmake(CMP0084-WARN)
run_cmake(CMP0084-NEW)
run_cmake(WrongVersionRange)
+run_cmake(EmptyVersionRange)
run_cmake(VersionRangeWithEXACT)
run_cmake(VersionRange)
run_cmake(VersionRange2)
run_cmake(VersionRange3)
+run_cmake(VersionRange4)
run_cmake(VersionRangeConfig)
run_cmake(VersionRangeConfig2)
run_cmake(VersionRangeConfigStd)
diff --git a/Tests/RunCMake/find_package/VersionRange.cmake b/Tests/RunCMake/find_package/VersionRange.cmake
index b3d8950..30b88a8 100644
--- a/Tests/RunCMake/find_package/VersionRange.cmake
+++ b/Tests/RunCMake/find_package/VersionRange.cmake
@@ -3,6 +3,11 @@ set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}")
set (VersionRange_SPECIFIED_VERSION_COMPLETE 1.2.3.4...5.6.7.8)
set (VersionRange_SPECIFIED_VERSION_RANGE 1.2.3.4...5.6.7.8)
+set (VersionRange_SPECIFIED_VERSION_MIN 1.2.3.4)
+set (VersionRange_SPECIFIED_VERSION_MIN_MAJOR 1)
+set (VersionRange_SPECIFIED_VERSION_MIN_MINOR 2)
+set (VersionRange_SPECIFIED_VERSION_MIN_PATCH 3)
+set (VersionRange_SPECIFIED_VERSION_MIN_TWEAK 4)
set (VersionRange_SPECIFIED_VERSION_MAX 5.6.7.8)
set (VersionRange_SPECIFIED_VERSION_MAX_MAJOR 5)
set (VersionRange_SPECIFIED_VERSION_MAX_MINOR 6)
diff --git a/Tests/RunCMake/find_package/VersionRange2.cmake b/Tests/RunCMake/find_package/VersionRange2.cmake
index d0e685b..9adcc64 100644
--- a/Tests/RunCMake/find_package/VersionRange2.cmake
+++ b/Tests/RunCMake/find_package/VersionRange2.cmake
@@ -3,6 +3,11 @@ set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}")
set (VersionRange_SPECIFIED_VERSION_COMPLETE 1.2.3.4...<5.6.7.8)
set (VersionRange_SPECIFIED_VERSION_RANGE 1.2.3.4...<5.6.7.8)
+set (VersionRange_SPECIFIED_VERSION_MIN 1.2.3.4)
+set (VersionRange_SPECIFIED_VERSION_MIN_MAJOR 1)
+set (VersionRange_SPECIFIED_VERSION_MIN_MINOR 2)
+set (VersionRange_SPECIFIED_VERSION_MIN_PATCH 3)
+set (VersionRange_SPECIFIED_VERSION_MIN_TWEAK 4)
set (VersionRange_SPECIFIED_VERSION_MAX 5.6.7.8)
set (VersionRange_SPECIFIED_VERSION_MAX_MAJOR 5)
set (VersionRange_SPECIFIED_VERSION_MAX_MINOR 6)
diff --git a/Tests/RunCMake/find_package/VersionRange3.cmake b/Tests/RunCMake/find_package/VersionRange3.cmake
index 76eef1d..41efac4 100644
--- a/Tests/RunCMake/find_package/VersionRange3.cmake
+++ b/Tests/RunCMake/find_package/VersionRange3.cmake
@@ -5,6 +5,11 @@ set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}")
set (VersionRange_SPECIFIED_VERSION_COMPLETE 1.2.3.4...<2.3.4.5)
set (VersionRange_SPECIFIED_VERSION_RANGE 1.2.3.4...<2.3.4.5)
+set (VersionRange_SPECIFIED_VERSION_MIN 1.2.3.4)
+set (VersionRange_SPECIFIED_VERSION_MIN_MAJOR 1)
+set (VersionRange_SPECIFIED_VERSION_MIN_MINOR 2)
+set (VersionRange_SPECIFIED_VERSION_MIN_PATCH 3)
+set (VersionRange_SPECIFIED_VERSION_MIN_TWEAK 4)
set (VersionRange_SPECIFIED_VERSION_MAX 2.3.4.5)
set (VersionRange_SPECIFIED_VERSION_MAX_MAJOR 2)
set (VersionRange_SPECIFIED_VERSION_MAX_MINOR 3)
diff --git a/Tests/RunCMake/find_package/VersionRange4.cmake b/Tests/RunCMake/find_package/VersionRange4.cmake
new file mode 100644
index 0000000..0953d04
--- /dev/null
+++ b/Tests/RunCMake/find_package/VersionRange4.cmake
@@ -0,0 +1,39 @@
+
+# show the effect of the exclusion or inclusion of the upper endpoint
+
+set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}")
+
+set (VersionRange_SPECIFIED_VERSION_COMPLETE 2.3.4.5...2.3.4.5)
+set (VersionRange_SPECIFIED_VERSION_RANGE 2.3.4.5...2.3.4.5)
+set (VersionRange_SPECIFIED_VERSION_MIN 2.3.4.5)
+set (VersionRange_SPECIFIED_VERSION_MIN_MAJOR 2)
+set (VersionRange_SPECIFIED_VERSION_MIN_MINOR 3)
+set (VersionRange_SPECIFIED_VERSION_MIN_PATCH 4)
+set (VersionRange_SPECIFIED_VERSION_MIN_TWEAK 5)
+set (VersionRange_SPECIFIED_VERSION_MAX 2.3.4.5)
+set (VersionRange_SPECIFIED_VERSION_MAX_MAJOR 2)
+set (VersionRange_SPECIFIED_VERSION_MAX_MINOR 3)
+set (VersionRange_SPECIFIED_VERSION_MAX_PATCH 4)
+set (VersionRange_SPECIFIED_VERSION_MAX_TWEAK 5)
+
+find_package (VersionRange ${VersionRange_SPECIFIED_VERSION_RANGE})
+
+if (NOT VersionRange_FOUND)
+ message (FATAL_ERROR "Package VersionRange not found.")
+endif()
+
+if (NOT VersionRange_VERSION VERSION_EQUAL "2.3.4.5")
+ message (SEND_ERROR "Wrong version : ${VersionRange_VERSION}")
+endif()
+if (NOT VersionRange_VERSION_MAJOR VERSION_EQUAL "2")
+ message (SEND_ERROR "Wrong major version : ${VersionRange_VERSION_MAJOR}")
+endif()
+if (NOT VersionRange_VERSION_MINOR VERSION_EQUAL "3")
+ message (SEND_ERROR "Wrong minor version : ${VersionRange_VERSION_MINOR}")
+endif()
+if (NOT VersionRange_VERSION_PATCH VERSION_EQUAL "4")
+ message (SEND_ERROR "Wrong patch version : ${VersionRange_VERSION_PATCH}")
+endif()
+if (NOT VersionRange_VERSION_TWEAK VERSION_EQUAL "5")
+ message (SEND_ERROR "Wrong tweak version : ${VersionRange_VERSION_TWEAK}")
+endif()
diff --git a/Utilities/cmlibuv/CMakeLists.txt b/Utilities/cmlibuv/CMakeLists.txt
index 7625cf6..92d2411 100644
--- a/Utilities/cmlibuv/CMakeLists.txt
+++ b/Utilities/cmlibuv/CMakeLists.txt
@@ -336,6 +336,24 @@ if(CMAKE_SYSTEM_NAME STREQUAL "HP-UX")
)
endif()
+if(CMAKE_SYSTEM_NAME STREQUAL "QNX")
+ list(APPEND uv_headers
+ include/uv/posix.h
+ )
+ list(APPEND uv_defines
+ _XOPEN_SOURCE=700
+ )
+ list(APPEND uv_sources
+ src/unix/posix-hrtime.c
+ src/unix/posix-poll.c
+ src/unix/no-fsevents.c
+ src/unix/no-proctitle.c
+ )
+ list(APPEND uv_libraries
+ socket
+ )
+endif()
+
include_directories(
${uv_includes}
${KWSYS_HEADER_ROOT}
diff --git a/bootstrap b/bootstrap
index 1e161db..feccde9 100755
--- a/bootstrap
+++ b/bootstrap
@@ -1675,6 +1675,10 @@ else
uv_c_flags="${uv_c_flags} -D__EXTENSIONS__ -D_XOPEN_SOURCE=600"
libs="${libs} -lkstat -lnsl -lsendfile -lsocket -lrt"
;;
+ *QNX*)
+ uv_c_flags="${uv_c_flags} -D_XOPEN_SOURCE=700"
+ libs="${libs} -lsocket"
+ ;;
esac
fi
if test "x${bootstrap_system_libuv}" = "x"; then